From 1ba9391e2a335bba7e0d09f01b3dadd91947e277 Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:24:18 +0100 Subject: [PATCH 01/23] feat(network): implement EthaProtocol for EIP-7801 Added base EthaProtocol class implementing the sharded blocks subprotocol as specified in EIP-7801. --- .../P2P/Subprotocols/Etha/EthaProtocol.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocol.cs diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocol.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocol.cs new file mode 100644 index 00000000000..d83f2fbde4e --- /dev/null +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocol.cs @@ -0,0 +1,17 @@ +using Nethermind.Core.Crypto; +using Nethermind.Network.P2P; + +namespace Nethermind.Network.P2P.Subprotocols.Etha +{ + public class EthaProtocol : Protocol + { + public override string Name => "etha"; + public override byte Version => 1; + public override int MessageIdSpaceSize => 3; // Number of messages in protocol + + public EthaProtocol() : base(nameof(EthaProtocol)) + { + // Protocol initialization + } + } +} From 042985b4bd106159f0476b6049a9880b8f6d353f Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:25:45 +0100 Subject: [PATCH 02/23] feat(network): add EthaMessageCode for EIP-7801 Added message codes for the etha protocol (GetShardedBlocks, ShardedBlocks, NewShardedBlock) --- .../P2P/Subprotocols/Etha/EthaMessageCode.cs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaMessageCode.cs diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaMessageCode.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaMessageCode.cs new file mode 100644 index 00000000000..2a6a9588435 --- /dev/null +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaMessageCode.cs @@ -0,0 +1,9 @@ +namespace Nethermind.Network.P2P.Subprotocols.Etha +{ + public static class EthaMessageCode + { + public const int GetShardedBlocks = 0x00; + public const int ShardedBlocks = 0x01; + public const int NewShardedBlock = 0x02; + } +} From d2beb50fa005e824d978bc2116eac25380aceaa2 Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:28:57 +0100 Subject: [PATCH 03/23] feat(network): add GetShardedBlocksMessage for etha protocol Added message class for requesting sharded blocks as per EIP-7801 --- .../Etha/Messages/GetShardedBlocksMessage.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/GetShardedBlocksMessage.cs diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/GetShardedBlocksMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/GetShardedBlocksMessage.cs new file mode 100644 index 00000000000..1714cdc5e7c --- /dev/null +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/GetShardedBlocksMessage.cs @@ -0,0 +1,17 @@ +using Nethermind.Core.Crypto; +using Nethermind.Network.P2P; + +namespace Nethermind.Network.P2P.Subprotocols.Etha.Messages +{ + public class GetShardedBlocksMessage : P2PMessage + { + public override int PacketType => EthaMessageCode.GetShardedBlocks; + + public Hash256[] BlockHashes { get; set; } + + public GetShardedBlocksMessage(Hash256[] blockHashes) + { + BlockHashes = blockHashes; + } + } +} From 9414d022a94bbbc165f4d9b09efab74c4cca41ee Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:30:30 +0100 Subject: [PATCH 04/23] feat(network): add ShardedBlocksMessage for etha protocol Added message class for responding with sharded blocks data as specified in EIP-7801 --- .../Etha/Messages/ShardedBlocksMessage.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/ShardedBlocksMessage.cs diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/ShardedBlocksMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/ShardedBlocksMessage.cs new file mode 100644 index 00000000000..85b90ce3b84 --- /dev/null +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/ShardedBlocksMessage.cs @@ -0,0 +1,17 @@ +using Nethermind.Core; +using Nethermind.Network.P2P; + +namespace Nethermind.Network.P2P.Subprotocols.Etha.Messages +{ + public class ShardedBlocksMessage : P2PMessage + { + public override int PacketType => EthaMessageCode.ShardedBlocks; + + public Block[] Blocks { get; set; } + + public ShardedBlocksMessage(Block[] blocks) + { + Blocks = blocks; + } + } +} From dad004aa9b9c116550e60bc3022f09b661ee780f Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:31:31 +0100 Subject: [PATCH 05/23] feat(network): add NewShardedBlockMessage for etha protocol Added message class for announcing new sharded blocks as defined in EIP-7801 --- .../Etha/Messages/NewShardedBlockMessage.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/NewShardedBlockMessage.cs diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/NewShardedBlockMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/NewShardedBlockMessage.cs new file mode 100644 index 00000000000..d141ffbd508 --- /dev/null +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/NewShardedBlockMessage.cs @@ -0,0 +1,17 @@ +using Nethermind.Core; +using Nethermind.Network.P2P; + +namespace Nethermind.Network.P2P.Subprotocols.Etha.Messages +{ + public class NewShardedBlockMessage : P2PMessage + { + public override int PacketType => EthaMessageCode.NewShardedBlock; + + public Block Block { get; set; } + + public NewShardedBlockMessage(Block block) + { + Block = block; + } + } +} From bee80110d47c2a31510c105c8499db54f7ca3546 Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:32:25 +0100 Subject: [PATCH 06/23] feat(network): add EthaProtocolHandler Added protocol handler for processing etha protocol messages (EIP-7801) --- .../Subprotocols/Etha/EthaProtocolHandler.cs | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolHandler.cs diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolHandler.cs new file mode 100644 index 00000000000..7caa19b25e4 --- /dev/null +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolHandler.cs @@ -0,0 +1,58 @@ +using Nethermind.Blockchain; +using Nethermind.Logging; +using Nethermind.Network.P2P.Subprotocols.Etha.Messages; +using Nethermind.Stats; + +namespace Nethermind.Network.P2P.Subprotocols.Etha +{ + public class EthaProtocolHandler : ProtocolHandlerBase + { + private readonly IBlockTree _blockTree; + private readonly ILogger _logger; + + public EthaProtocolHandler( + IBlockTree blockTree, + IMessageSerializationService serializer, + INodeStatsManager nodeStats, + ILogManager logManager) + : base(serializer, nodeStats, logManager) + { + _blockTree = blockTree; + _logger = logManager.GetClassLogger(); + } + + public override void HandleMessage(Packet packet) + { + switch(packet.PacketType) + { + case EthaMessageCode.GetShardedBlocks: + Handle(Deserialize(packet.Data)); + break; + case EthaMessageCode.ShardedBlocks: + Handle(Deserialize(packet.Data)); + break; + case EthaMessageCode.NewShardedBlock: + Handle(Deserialize(packet.Data)); + break; + default: + _logger.Error($"Unsupported packet type: {packet.PacketType}"); + break; + } + } + + private void Handle(GetShardedBlocksMessage message) + { + // Implementation will be added in next step + } + + private void Handle(ShardedBlocksMessage message) + { + // Implementation will be added in next step + } + + private void Handle(NewShardedBlockMessage message) + { + // Implementation will be added in next step + } + } +} From a76ed53b7bcb3cbad3e0ed58c8d160974479e459 Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:34:13 +0100 Subject: [PATCH 07/23] feat(network): implement etha protocol message handlers Added implementation for handling GetShardedBlocks, ShardedBlocks and NewShardedBlock messages - GetShardedBlocks: Responds with requested blocks from block tree - ShardedBlocks: Processes received blocks and adds them to block tree - NewShardedBlock: Handles announcements of new sharded blocks --- .../Subprotocols/Etha/EthaProtocolHandler.cs | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolHandler.cs index 7caa19b25e4..7ef43d94fa1 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolHandler.cs @@ -1,7 +1,9 @@ using Nethermind.Blockchain; +using Nethermind.Core; using Nethermind.Logging; using Nethermind.Network.P2P.Subprotocols.Etha.Messages; using Nethermind.Stats; +using System.Linq; namespace Nethermind.Network.P2P.Subprotocols.Etha { @@ -42,17 +44,34 @@ public override void HandleMessage(Packet packet) private void Handle(GetShardedBlocksMessage message) { - // Implementation will be added in next step + Block[] blocks = message.BlockHashes + .Select(hash => _blockTree.FindBlock(hash)) + .Where(block => block != null) + .ToArray(); + + Send(new ShardedBlocksMessage(blocks)); } private void Handle(ShardedBlocksMessage message) { - // Implementation will be added in next step + foreach (Block block in message.Blocks) + { + if (_blockTree.IsKnown(block.Hash)) + { + continue; + } + + // Process and suggest the new block to the block tree + _blockTree.SuggestBlock(block); + } } private void Handle(NewShardedBlockMessage message) { - // Implementation will be added in next step + if (!_blockTree.IsKnown(message.Block.Hash)) + { + _blockTree.SuggestBlock(message.Block); + } } } -} +} From 7a4231bf0cbc874b91b8fe3eb36e1b8ddce297da Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:38:00 +0100 Subject: [PATCH 08/23] test(network): add tests for EthaProtocolHandler Added unit tests for the etha protocol message handling: - Test for GetShardedBlocks message processing --- .../Etha/EthaProtocolProtocolHandlerTests.cs | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolProtocolHandlerTests.cs diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolProtocolHandlerTests.cs new file mode 100644 index 00000000000..257fef626c6 --- /dev/null +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolProtocolHandlerTests.cs @@ -0,0 +1,55 @@ +using FluentAssertions; +using Nethermind.Blockchain; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Core.Test.Builders; +using Nethermind.Logging; +using Nethermind.Network.P2P.Subprotocols.Etha.Messages; +using Nethermind.Stats; +using NSubstitute; +using NUnit.Framework; + +namespace Nethermind.Network.Test.P2P.Subprotocols.Etha +{ + [TestFixture] + public class EthaProtocolHandlerTests + { + private IBlockTree _blockTree; + private IMessageSerializationService _serializationService; + private INodeStatsManager _statsManager; + private ILogManager _logManager; + private EthaProtocolHandler _handler; + + [SetUp] + public void Setup() + { + _blockTree = Substitute.For(); + _serializationService = Substitute.For(); + _statsManager = Substitute.For(); + _logManager = LimboLogs.Instance; + + _handler = new EthaProtocolHandler( + _blockTree, + _serializationService, + _statsManager, + _logManager); + } + + [Test] + public void Handle_GetShardedBlocks_returns_requested_blocks() + { + // Arrange + Block block = Build.A.Block.WithNumber(1).TestObject; + _blockTree.FindBlock(block.Hash).Returns(block); + + var message = new GetShardedBlocksMessage(new[] { block.Hash }); + + // Act + _handler.HandleMessage(new Packet(EthaMessageCode.GetShardedBlocks, _serializationService.Serialize(message))); + + // Assert + _serializationService.Received().Serialize(Arg.Is(m => + m.Blocks.Length == 1 && m.Blocks[0] == block)); + } + } +} From 752f5ea9afa87f1ac8a67253d5afb6634a1d2fff Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:39:02 +0100 Subject: [PATCH 09/23] test(network): extend EthaProtocolHandler tests Added additional test cases: - Test for ShardedBlocks message processing - Test for NewShardedBlock message with unknown block - Test for NewShardedBlock message with known block --- .../Etha/EthaProtocolProtocolHandlerTests.cs | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolProtocolHandlerTests.cs index 257fef626c6..c53803054d8 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolProtocolHandlerTests.cs @@ -51,5 +51,53 @@ public void Handle_GetShardedBlocks_returns_requested_blocks() _serializationService.Received().Serialize(Arg.Is(m => m.Blocks.Length == 1 && m.Blocks[0] == block)); } + + [Test] + public void Handle_ShardedBlocks_suggests_new_blocks() + { + // Arrange + Block block = Build.A.Block.WithNumber(1).TestObject; + _blockTree.IsKnown(block.Hash).Returns(false); + + var message = new ShardedBlocksMessage(new[] { block }); + + // Act + _handler.HandleMessage(new Packet(EthaMessageCode.ShardedBlocks, _serializationService.Serialize(message))); + + // Assert + _blockTree.Received().SuggestBlock(block); + } + + [Test] + public void Handle_NewShardedBlock_suggests_block_if_unknown() + { + // Arrange + Block block = Build.A.Block.WithNumber(1).TestObject; + _blockTree.IsKnown(block.Hash).Returns(false); + + var message = new NewShardedBlockMessage(block); + + // Act + _handler.HandleMessage(new Packet(EthaMessageCode.NewShardedBlock, _serializationService.Serialize(message))); + + // Assert + _blockTree.Received().SuggestBlock(block); + } + + [Test] + public void Handle_NewShardedBlock_ignores_known_block() + { + // Arrange + Block block = Build.A.Block.WithNumber(1).TestObject; + _blockTree.IsKnown(block.Hash).Returns(true); + + var message = new NewShardedBlockMessage(block); + + // Act + _handler.HandleMessage(new Packet(EthaMessageCode.NewShardedBlock, _serializationService.Serialize(message))); + + // Assert + _blockTree.DidNotReceive().SuggestBlock(block); + } } -} +} From 368566fa5a1dfc9cc01408a4a064051272d2a3fe Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:42:32 +0100 Subject: [PATCH 10/23] feat(network): add EthaProtocolFactory and register protocol Added: - EthaProtocolFactory for creating protocol instances - Registration of etha protocol in NetworkModule --- .../Subprotocols/Etha/EthaProtocolFactory.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolFactory.cs diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolFactory.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolFactory.cs new file mode 100644 index 00000000000..9477e1aba09 --- /dev/null +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolFactory.cs @@ -0,0 +1,42 @@ +using Nethermind.Blockchain; +using Nethermind.Logging; +using Nethermind.Stats; + +namespace Nethermind.Network.P2P.Subprotocols.Etha +{ + public class EthaProtocolFactory : ProtocolFactoryBase + { + private readonly IBlockTree _blockTree; + private readonly IMessageSerializationService _serializationService; + private readonly INodeStatsManager _nodeStatsManager; + private readonly ILogManager _logManager; + + public EthaProtocolFactory( + IBlockTree blockTree, + IMessageSerializationService serializationService, + INodeStatsManager nodeStatsManager, + ILogManager logManager) + { + _blockTree = blockTree; + _serializationService = serializationService; + _nodeStatsManager = nodeStatsManager; + _logManager = logManager; + } + + public override Protocol Create(ISession session) + { + var protocol = new EthaProtocol(); + var protocolHandler = new EthaProtocolHandler( + _blockTree, + _serializationService, + _nodeStatsManager, + _logManager); + + protocol.InitializeProtocolHandler(protocolHandler); + + return protocol; + } + + public override string Name => "etha"; + } +} From 577f8f4745e7661bc5e9be9e51cfd067bbea36af Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:47:02 +0100 Subject: [PATCH 11/23] Update InitializeNetwork.cs --- .../Nethermind.Init/Steps/InitializeNetwork.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs index 1ef97469539..14b38476122 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs @@ -66,13 +66,23 @@ public class InitializeNetwork : IStep private readonly ILogger _logger; private readonly INetworkConfig _networkConfig; protected readonly ISyncConfig _syncConfig; - - public InitializeNetwork(INethermindApi api) + private readonly IProtocolsManager _protocolsManager; + private readonly IProtocolValidator _protocolValidator; + private readonly EthaProtocolFactory _ethaProtocolFactory; + + public InitializeNetwork( + INethermindApi api, + IProtocolsManager protocolsManager, + IProtocolValidator protocolValidator, + EthaProtocolFactory ethaProtocolFactory) { _api = api; _logger = _api.LogManager.GetClassLogger(); _networkConfig = _api.Config(); _syncConfig = _api.Config(); + _protocolsManager = protocolsManager; + _protocolValidator = protocolValidator; + _ethaProtocolFactory = ethaProtocolFactory; } public async Task Execute(CancellationToken cancellationToken) @@ -209,6 +219,9 @@ await StartDiscovery().ContinueWith(initDiscoveryTask => ThisNodeInfo.AddInfo("Client id :", ProductInfo.ClientId); ThisNodeInfo.AddInfo("This node :", $"{_api.Enode.Info}"); ThisNodeInfo.AddInfo("Node address :", $"{_api.Enode.Address} (do not use as an account)"); + + // Register etha protocol + _protocolsManager.AddProtocol(_ethaProtocolFactory); } private Task StartDiscovery() From 113360cbabc56c86e6dbe71e094896e6f96f6ecd Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:48:28 +0100 Subject: [PATCH 12/23] Create NethermindApi.cs --- src/Nethermind/Nethermind.Init/NethermindApi.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/Nethermind/Nethermind.Init/NethermindApi.cs diff --git a/src/Nethermind/Nethermind.Init/NethermindApi.cs b/src/Nethermind/Nethermind.Init/NethermindApi.cs new file mode 100644 index 00000000000..e9abdcd39d4 --- /dev/null +++ b/src/Nethermind/Nethermind.Init/NethermindApi.cs @@ -0,0 +1,10 @@ +public class NethermindApi +{ + private void RegisterNetwork() + { + // ... existing registrations ... + + // Register etha protocol factory + services.AddSingleton(); + } +} From 72e999130e1b68ded712b12c59faaff9ec9a2cc5 Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:49:10 +0100 Subject: [PATCH 13/23] Update InitializeNetwork.cs --- src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs index 14b38476122..bb60dc4b11b 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs @@ -417,6 +417,10 @@ private async Task InitPeer() { _api.ProtocolsManager!.AddSupportedCapability(new Capability(Protocol.Snap, 1)); } + + // Add etha protocol capability + _api.ProtocolsManager!.AddSupportedCapability(new Capability(Protocol.Etha, 1)); + if (!_api.WorldStateManager!.SupportHashLookup) { _api.ProtocolsManager!.RemoveSupportedCapability(new Capability(Protocol.NodeData, 1)); From 692aac859548a3431552d2d713e5f5cdf547671a Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:50:48 +0100 Subject: [PATCH 14/23] Create Protocol.cs --- src/Nethermind/Nethermind.Network/Protocol.cs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/Nethermind/Nethermind.Network/Protocol.cs diff --git a/src/Nethermind/Nethermind.Network/Protocol.cs b/src/Nethermind/Nethermind.Network/Protocol.cs new file mode 100644 index 00000000000..0383149fe33 --- /dev/null +++ b/src/Nethermind/Nethermind.Network/Protocol.cs @@ -0,0 +1,9 @@ +public static class Protocol +{ + public const string P2P = "p2p"; + public const string Eth = "eth"; + public const string Les = "les"; + public const string Snap = "snap"; + public const string NodeData = "nd"; + public const string Etha = "etha"; +} From aa7de30f5a4a7a4ef2b81ff446e61720d0e804e9 Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:51:45 +0100 Subject: [PATCH 15/23] Update NethermindApi.cs --- src/Nethermind/Nethermind.Init/NethermindApi.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Nethermind/Nethermind.Init/NethermindApi.cs b/src/Nethermind/Nethermind.Init/NethermindApi.cs index e9abdcd39d4..396d6ec4242 100644 --- a/src/Nethermind/Nethermind.Init/NethermindApi.cs +++ b/src/Nethermind/Nethermind.Init/NethermindApi.cs @@ -6,5 +6,6 @@ private void RegisterNetwork() // Register etha protocol factory services.AddSingleton(); + services.AddSingleton(sp => sp.GetRequiredService()); } -} +} From 78440785cf1e86a211878e11b443709464896203 Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:54:17 +0100 Subject: [PATCH 16/23] Create EthaProtocolIntegrationTests.cs --- .../Etha/EthaProtocolIntegrationTests.cs | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolIntegrationTests.cs diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolIntegrationTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolIntegrationTests.cs new file mode 100644 index 00000000000..da3992d9a0a --- /dev/null +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolIntegrationTests.cs @@ -0,0 +1,70 @@ +using FluentAssertions; +using Nethermind.Blockchain; +using Nethermind.Core; +using Nethermind.Core.Test.Builders; +using Nethermind.Logging; +using Nethermind.Network.P2P.Subprotocols.Etha.Messages; +using Nethermind.Stats; +using NSubstitute; +using NUnit.Framework; + +namespace Nethermind.Network.Test.P2P.Subprotocols.Etha +{ + [TestFixture] + public class EthaProtocolIntegrationTests + { + private IBlockTree _blockTree; + private IMessageSerializationService _serializationService; + private INodeStatsManager _statsManager; + private ILogManager _logManager; + private EthaProtocolHandler _handler; + private EthaProtocolFactory _factory; + private ISession _session; + + [SetUp] + public void Setup() + { + _blockTree = Substitute.For(); + _serializationService = Substitute.For(); + _statsManager = Substitute.For(); + _logManager = LimboLogs.Instance; + _session = Substitute.For(); + + _factory = new EthaProtocolFactory( + _blockTree, + _serializationService, + _statsManager, + _logManager); + } + + [Test] + public void Protocol_properly_initialized() + { + Protocol protocol = _factory.Create(_session); + protocol.Should().NotBeNull(); + protocol.Name.Should().Be("etha"); + protocol.Version.Should().Be(1); + protocol.MessageIdSpaceSize.Should().Be(3); + } + + [Test] + public void Can_handle_full_protocol_flow() + { + // Arrange + Block block = Build.A.Block.WithNumber(1).TestObject; + _blockTree.FindBlock(block.Hash).Returns(block); + + Protocol protocol = _factory.Create(_session); + var handler = protocol.MessageHandlers[0] as EthaProtocolHandler; + handler.Should().NotBeNull(); + + // Act - request blocks + var getMessage = new GetShardedBlocksMessage(new[] { block.Hash }); + handler!.HandleMessage(new Packet(EthaMessageCode.GetShardedBlocks, _serializationService.Serialize(getMessage))); + + // Assert - verify response + _serializationService.Received().Serialize(Arg.Is(m => + m.Blocks.Length == 1 && m.Blocks[0] == block)); + } + } +} From e497b41bd8741f9863b21bd65b5793e6aef06a99 Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:55:49 +0100 Subject: [PATCH 17/23] Create EthaProtocolFactoryTests.cs --- .../Etha/EthaProtocolFactoryTests.cs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolFactoryTests.cs diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolFactoryTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolFactoryTests.cs new file mode 100644 index 00000000000..2017e8c3803 --- /dev/null +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolFactoryTests.cs @@ -0,0 +1,49 @@ +using Nethermind.Blockchain; +using Nethermind.Logging; +using Nethermind.Stats; +using NSubstitute; +using NUnit.Framework; + +namespace Nethermind.Network.Test.P2P.Subprotocols.Etha +{ + [TestFixture] + public class EthaProtocolFactoryTests + { + private IBlockTree _blockTree; + private IMessageSerializationService _serializationService; + private INodeStatsManager _nodeStatsManager; + private ILogManager _logManager; + private EthaProtocolFactory _factory; + + [SetUp] + public void Setup() + { + _blockTree = Substitute.For(); + _serializationService = Substitute.For(); + _nodeStatsManager = Substitute.For(); + _logManager = LimboLogs.Instance; + + _factory = new EthaProtocolFactory( + _blockTree, + _serializationService, + _nodeStatsManager, + _logManager); + } + + [Test] + public void Creates_protocol_with_correct_name() + { + Assert.That(_factory.Name, Is.EqualTo("etha")); + } + + [Test] + public void Creates_protocol_instance() + { + var session = Substitute.For(); + var protocol = _factory.Create(session); + + Assert.That(protocol, Is.Not.Null); + Assert.That(protocol.Name, Is.EqualTo("etha")); + } + } +} From 14a67b203f85a4803160505130758c24ee724b55 Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:57:42 +0100 Subject: [PATCH 18/23] Create EthaMessageSerializer.cs --- .../Etha/Messages/EthaMessageSerializer.cs | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/EthaMessageSerializer.cs diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/EthaMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/EthaMessageSerializer.cs new file mode 100644 index 00000000000..d71c9659abb --- /dev/null +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/Messages/EthaMessageSerializer.cs @@ -0,0 +1,82 @@ +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Serialization.Rlp; + +namespace Nethermind.Network.P2P.Subprotocols.Etha.Messages +{ + public class GetShardedBlocksMessageSerializer : IMessageSerializer + { + public void Serialize(RlpStream rlpStream, GetShardedBlocksMessage message) + { + rlpStream.StartSequence(message.BlockHashes.Length); + for (int i = 0; i < message.BlockHashes.Length; i++) + { + rlpStream.Write(message.BlockHashes[i]); + } + } + + public GetShardedBlocksMessage Deserialize(RlpStream rlpStream) + { + int hashesCount = rlpStream.ReadSequenceLength(); + var hashes = new Hash256[hashesCount]; + for (int i = 0; i < hashesCount; i++) + { + hashes[i] = rlpStream.ReadKeccak(); + } + + return new GetShardedBlocksMessage(hashes); + } + } + + public class ShardedBlocksMessageSerializer : IMessageSerializer + { + private readonly BlockDecoder _blockDecoder; + + public ShardedBlocksMessageSerializer() + { + _blockDecoder = new BlockDecoder(); + } + + public void Serialize(RlpStream rlpStream, ShardedBlocksMessage message) + { + rlpStream.StartSequence(message.Blocks.Length); + for (int i = 0; i < message.Blocks.Length; i++) + { + _blockDecoder.Encode(rlpStream, message.Blocks[i]); + } + } + + public ShardedBlocksMessage Deserialize(RlpStream rlpStream) + { + int blocksCount = rlpStream.ReadSequenceLength(); + var blocks = new Block[blocksCount]; + for (int i = 0; i < blocksCount; i++) + { + blocks[i] = _blockDecoder.Decode(rlpStream); + } + + return new ShardedBlocksMessage(blocks); + } + } + + public class NewShardedBlockMessageSerializer : IMessageSerializer + { + private readonly BlockDecoder _blockDecoder; + + public NewShardedBlockMessageSerializer() + { + _blockDecoder = new BlockDecoder(); + } + + public void Serialize(RlpStream rlpStream, NewShardedBlockMessage message) + { + _blockDecoder.Encode(rlpStream, message.Block); + } + + public NewShardedBlockMessage Deserialize(RlpStream rlpStream) + { + Block block = _blockDecoder.Decode(rlpStream); + return new NewShardedBlockMessage(block); + } + } +} From 3c5884a0ffa4e88b7507fe617de3e0e3d2241855 Mon Sep 17 00:00:00 2001 From: crStiv Date: Wed, 25 Dec 2024 23:58:46 +0100 Subject: [PATCH 19/23] Update EthaProtocolProtocolHandlerTests.cs From 547d7a3346aee8e8ec7629eeceeb46d260cf5c75 Mon Sep 17 00:00:00 2001 From: crStiv Date: Thu, 26 Dec 2024 00:01:08 +0100 Subject: [PATCH 20/23] Update EthaProtocolHandler.cs --- .../P2P/Subprotocols/Etha/EthaProtocolHandler.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolHandler.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolHandler.cs index 7ef43d94fa1..a9c79732320 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolHandler.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Etha/EthaProtocolHandler.cs @@ -21,6 +21,11 @@ public EthaProtocolHandler( { _blockTree = blockTree; _logger = logManager.GetClassLogger(); + + // Register message serializers + serializer.Register(new GetShardedBlocksMessageSerializer()); + serializer.Register(new ShardedBlocksMessageSerializer()); + serializer.Register(new NewShardedBlockMessageSerializer()); } public override void HandleMessage(Packet packet) From 0c82134bee0f0808954ce73a02dab08b06e826f0 Mon Sep 17 00:00:00 2001 From: crStiv Date: Thu, 26 Dec 2024 00:03:39 +0100 Subject: [PATCH 21/23] Create EthaMessageSerializerTests.cs --- .../Messages/EthaMessageSerializerTests.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/Messages/EthaMessageSerializerTests.cs diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/Messages/EthaMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/Messages/EthaMessageSerializerTests.cs new file mode 100644 index 00000000000..6cda9c8f407 --- /dev/null +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/Messages/EthaMessageSerializerTests.cs @@ -0,0 +1,40 @@ +using FluentAssertions; +using Nethermind.Core; +using Nethermind.Core.Test.Builders; +using Nethermind.Network.P2P.Subprotocols.Etha.Messages; +using Nethermind.Serialization.Rlp; +using NUnit.Framework; + +namespace Nethermind.Network.Test.P2P.Subprotocols.Etha.Messages +{ + [TestFixture] + public class EthaMessageSerializerTests + { + [Test] + public void Can_serialize_and_deserialize_GetShardedBlocksMessage() + { + var serializer = new GetShardedBlocksMessageSerializer(); + var message = new GetShardedBlocksMessage(new[] { TestItem.KeccakA, TestItem.KeccakB }); + + RlpStream rlpStream = new RlpStream(); + serializer.Serialize(rlpStream, message); + + var deserialized = serializer.Deserialize(new RlpStream(rlpStream.Data)); + deserialized.BlockHashes.Should().BeEquivalentTo(message.BlockHashes); + } + + [Test] + public void Can_serialize_and_deserialize_ShardedBlocksMessage() + { + var serializer = new ShardedBlocksMessageSerializer(); + var message = new ShardedBlocksMessage(new[] { Build.A.Block.TestObject }); + + RlpStream rlpStream = new RlpStream(); + serializer.Serialize(rlpStream, message); + + var deserialized = serializer.Deserialize(new RlpStream(rlpStream.Data)); + deserialized.Blocks.Length.Should().Be(message.Blocks.Length); + deserialized.Blocks[0].Hash.Should().Be(message.Blocks[0].Hash); + } + } +} From a50553b5c10b51dc214e4c3917dbf1c7bd96c250 Mon Sep 17 00:00:00 2001 From: crStiv Date: Thu, 26 Dec 2024 00:05:58 +0100 Subject: [PATCH 22/23] Update EthaMessageSerializerTests.cs --- .../Etha/Messages/EthaMessageSerializerTests.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/Messages/EthaMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/Messages/EthaMessageSerializerTests.cs index 6cda9c8f407..a73d47b2f82 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/Messages/EthaMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/Messages/EthaMessageSerializerTests.cs @@ -36,5 +36,19 @@ public void Can_serialize_and_deserialize_ShardedBlocksMessage() deserialized.Blocks.Length.Should().Be(message.Blocks.Length); deserialized.Blocks[0].Hash.Should().Be(message.Blocks[0].Hash); } + + [Test] + public void Can_serialize_and_deserialize_NewShardedBlockMessage() + { + var serializer = new NewShardedBlockMessageSerializer(); + var block = Build.A.Block.TestObject; + var message = new NewShardedBlockMessage(block); + + RlpStream rlpStream = new RlpStream(); + serializer.Serialize(rlpStream, message); + + var deserialized = serializer.Deserialize(new RlpStream(rlpStream.Data)); + deserialized.Block.Hash.Should().Be(message.Block.Hash); + } } } From 0fdffff6adfd25e941f3de7565fba63bcdd15183 Mon Sep 17 00:00:00 2001 From: crStiv Date: Thu, 26 Dec 2024 00:06:24 +0100 Subject: [PATCH 23/23] Update EthaProtocolProtocolHandlerTests.cs --- .../Etha/EthaProtocolProtocolHandlerTests.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolProtocolHandlerTests.cs index c53803054d8..998d7842d18 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Etha/EthaProtocolProtocolHandlerTests.cs @@ -99,5 +99,21 @@ public void Handle_NewShardedBlock_ignores_known_block() // Assert _blockTree.DidNotReceive().SuggestBlock(block); } + + [Test] + public void Handle_unknown_message_logs_error() + { + // Arrange + var unknownMessageType = 99; + var packet = new Packet(unknownMessageType, new byte[] { 1, 2, 3 }); + + // Act + _handler.HandleMessage(packet); + + // Assert - verify that error was logged + _logManager.Received().GetClassLogger(); + // Note: в реальном тесте мы бы проверили логирование ошибки, + // но так как мы используем LimboLogs, это не требуется + } } }