From 5bea10375b51ef29e8281af71f5f55ea7444e9c4 Mon Sep 17 00:00:00 2001 From: Shargon Date: Sun, 6 Sep 2020 15:48:27 +0200 Subject: [PATCH] Add block receive height limit (#1870) * Add block cache limit * Remove known hashes * Optimize * Update Blockchain.cs * Clean code * Rename method * Prevent process far blocks * Block ACL * Remove size control https://github.com/neo-project/neo/pull/1870#discussion_r480079809 * Move knownHashes * Remove no sender * Rename * Rename * Update RemoteNode.ProtocolHandler.cs Co-authored-by: erikzhang --- src/neo/Ledger/Blockchain.cs | 35 +++++++++++++------ .../Network/P2P/RemoteNode.ProtocolHandler.cs | 7 ++-- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index f186d9363f..3c27ecfacc 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -1,5 +1,6 @@ using Akka.Actor; using Akka.Configuration; +using Akka.IO; using Neo.Cryptography.ECC; using Neo.IO; using Neo.IO.Actors; @@ -28,6 +29,7 @@ public class FillMemoryPool { public IEnumerable Transactions; } public class FillCompleted { } internal class PreverifyCompleted { public Transaction Transaction; public VerifyResult Result; public bool Relay; } public class RelayResult { public IInventory Inventory; public VerifyResult Result; } + private class UnverifiedBlocksList { public LinkedList Blocks = new LinkedList(); public HashSet Nodes = new HashSet(); } public static readonly uint MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock; public static readonly TimeSpan TimePerBlock = TimeSpan.FromMilliseconds(MillisecondsPerBlock); @@ -61,7 +63,7 @@ public class RelayResult { public IInventory Inventory; public VerifyResult Resu private readonly List header_index = new List(); private uint stored_header_count = 0; private readonly Dictionary block_cache = new Dictionary(); - private readonly Dictionary> block_cache_unverified = new Dictionary>(); + private readonly Dictionary block_cache_unverified = new Dictionary(); internal readonly RelayCache RelayCache = new RelayCache(100); private SnapshotView currentSnapshot; @@ -273,19 +275,30 @@ private void OnImport(IEnumerable blocks, bool verify) private void AddUnverifiedBlockToCache(Block block) { // Check if any block proposal for height `block.Index` exists - if (!block_cache_unverified.TryGetValue(block.Index, out LinkedList blocks)) + if (!block_cache_unverified.TryGetValue(block.Index, out var list)) { - // There are no blocks, a new LinkedList is created and, consequently, the current block is added to the list - blocks = new LinkedList(); - block_cache_unverified.Add(block.Index, blocks); + // There are no blocks, a new UnverifiedBlocksList is created and, consequently, the current block is added to the list + list = new UnverifiedBlocksList(); + block_cache_unverified.Add(block.Index, list); } - // Check if any block with the hash being added already exists on possible candidates to be processed - foreach (var unverifiedBlock in blocks) + else { - if (block.Hash == unverifiedBlock.Hash) + // Check if any block with the hash being added already exists on possible candidates to be processed + foreach (var unverifiedBlock in list.Blocks) + { + if (block.Hash == unverifiedBlock.Hash) + return; + } + + if (!list.Nodes.Add(Sender)) + { + // Same index with different hash + Sender.Tell(Tcp.Abort.Instance); return; + } } - blocks.AddLast(block); + + list.Blocks.AddLast(block); } private void OnFillMemoryPool(IEnumerable transactions) @@ -340,9 +353,9 @@ private VerifyResult OnNewBlock(Block block) system.LocalNode.Tell(Message.Create(MessageCommand.Ping, PingPayload.Create(Singleton.Height + 1))); Persist(block); SaveHeaderHashList(); - if (block_cache_unverified.TryGetValue(Height + 1, out LinkedList unverifiedBlocks)) + if (block_cache_unverified.TryGetValue(Height + 1, out var unverifiedBlocks)) { - foreach (var unverifiedBlock in unverifiedBlocks) + foreach (var unverifiedBlock in unverifiedBlocks.Blocks) Self.Tell(unverifiedBlock, ActorRefs.NoSender); block_cache_unverified.Remove(Height + 1); } diff --git a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs index 0cddbd49d7..2c3a6c5682 100644 --- a/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -287,18 +287,19 @@ private void OnGetHeadersMessageReceived(GetBlockByIndexPayload payload) private void OnInventoryReceived(IInventory inventory) { pendingKnownHashes.Remove(inventory.Hash); - knownHashes.Add(inventory.Hash); - system.TaskManager.Tell(inventory); - system.Blockchain.Tell(inventory, ActorRefs.NoSender); switch (inventory) { case Transaction transaction: system.Consensus?.Tell(transaction); break; case Block block: + if (block.Index > Blockchain.Singleton.Height + InvPayload.MaxHashesCount) return; UpdateLastBlockIndex(block.Index, false); break; } + knownHashes.Add(inventory.Hash); + system.TaskManager.Tell(inventory); + system.Blockchain.Tell(inventory); } private void OnInvMessageReceived(InvPayload payload)