diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/Ethash.cs b/src/Nethermind/Nethermind.Consensus.Ethash/Ethash.cs index 7a48e064867..3d243d92bb5 100644 --- a/src/Nethermind/Nethermind.Consensus.Ethash/Ethash.cs +++ b/src/Nethermind/Nethermind.Consensus.Ethash/Ethash.cs @@ -151,11 +151,11 @@ private static ulong GetRandomNonce() return BitConverter.ToUInt64(buffer, 0); } - private bool IsLessThanTarget(byte[] result, UInt256 difficulty) + private bool IsLessOrEqualThanTarget(byte[] result, UInt256 difficulty) { UInt256 resultAsInteger = new(result, true); - BigInteger threshold = BigInteger.Divide(_2To256, (BigInteger)difficulty); - return (BigInteger)resultAsInteger < threshold; + BigInteger target = BigInteger.Divide(_2To256, (BigInteger)difficulty); + return (BigInteger)resultAsInteger <= target; } public (Keccak MixHash, ulong Nonce) Mine(BlockHeader header, ulong? startNonce = null) @@ -178,7 +178,7 @@ private bool IsLessThanTarget(byte[] result, UInt256 difficulty) { byte[] result; (mixHash, result, _) = Hashimoto(fullSize, dataSet, headerHashed, null, nonce); - if (IsLessThanTarget(result, header.Difficulty)) + if (IsLessOrEqualThanTarget(result, header.Difficulty)) { break; } @@ -243,7 +243,7 @@ public bool Validate(BlockHeader header) return false; } - return IsLessThanTarget(result, header.Difficulty); + return IsLessOrEqualThanTarget(result, header.Difficulty); } private readonly Stopwatch _cacheStopwatch = new(); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs index 722f85da909..0626491c027 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs @@ -24,6 +24,7 @@ using Nethermind.Blockchain.Receipts; using Nethermind.Blockchain.Synchronization; using Nethermind.Blockchain.Validators; +using Nethermind.Config; using Nethermind.Consensus; using Nethermind.Core; using Nethermind.Core.Crypto; @@ -48,6 +49,7 @@ using Nethermind.Trie.Pruning; using Nethermind.TxPool; using NSubstitute; +using NSubstitute.Exceptions; using NUnit.Framework; using BlockTree = Nethermind.Blockchain.BlockTree; @@ -76,11 +78,11 @@ public class BlockDownloaderTests [TestCase(SyncBatchSize.Max * 8, DownloaderOptions.Process, 32)] public async Task Happy_path(long headNumber, int options, int threshold) { - Context ctx = new Context(); + Context ctx = new(); DownloaderOptions downloaderOptions = (DownloaderOptions) options; bool withReceipts = downloaderOptions == DownloaderOptions.WithReceipts; - InMemoryReceiptStorage receiptStorage = new InMemoryReceiptStorage(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, receiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); + InMemoryReceiptStorage receiptStorage = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, receiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); Response responseOptions = Response.AllCorrect; if (withReceipts) @@ -91,9 +93,9 @@ public async Task Happy_path(long headNumber, int options, int threshold) // normally chain length should be head number + 1 so here we setup a slightly shorter chain which // will only be fixed slightly later long chainLength = headNumber + 1; - SyncPeerMock syncPeer = new SyncPeerMock(chainLength, withReceipts, responseOptions); + SyncPeerMock syncPeer = new(chainLength, withReceipts, responseOptions); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.None, threshold), CancellationToken.None); ctx.BlockTree.BestSuggestedHeader.Number.Should().Be(Math.Max(0, Math.Min(headNumber, headNumber - threshold))); @@ -118,21 +120,21 @@ public async Task Happy_path(long headNumber, int options, int threshold) [Test] public async Task Ancestor_lookup_simple() { - InMemoryReceiptStorage inMemoryReceiptStorage = new InMemoryReceiptStorage(); + InMemoryReceiptStorage inMemoryReceiptStorage = new(); - Context ctx = new Context(); + Context ctx = new(); ctx.BlockTree = Build.A.BlockTree().OfChainLength(1024).TestObject; ISyncPeerPool syncPeerPool = Substitute.For(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, syncPeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); + BlockDownloader downloader = new(ctx.Feed, syncPeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); Response blockResponseOptions = Response.AllCorrect; - SyncPeerMock syncPeer = new SyncPeerMock(2048 + 1, false, blockResponseOptions); + SyncPeerMock syncPeer = new(2048 + 1, false, blockResponseOptions); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); - var block1024 = Build.A.Block.WithParent(ctx.BlockTree.Head).WithDifficulty(ctx.BlockTree.Head.Difficulty + 1).TestObject; - var block1025 = Build.A.Block.WithParent(block1024).WithDifficulty(block1024.Difficulty + 1).TestObject; - var block1026 = Build.A.Block.WithParent(block1025).WithDifficulty(block1025.Difficulty + 1).TestObject; + Block block1024 = Build.A.Block.WithParent(ctx.BlockTree.Head).WithDifficulty(ctx.BlockTree.Head.Difficulty + 1).TestObject; + Block block1025 = Build.A.Block.WithParent(block1024).WithDifficulty(block1024.Difficulty + 1).TestObject; + Block block1026 = Build.A.Block.WithParent(block1025).WithDifficulty(block1025.Difficulty + 1).TestObject; ctx.BlockTree.SuggestBlock(block1024); ctx.BlockTree.SuggestBlock(block1025); ctx.BlockTree.SuggestBlock(block1026); @@ -150,19 +152,19 @@ public async Task Ancestor_lookup_simple() [Test] public async Task Ancestor_lookup_headers() { - InMemoryReceiptStorage inMemoryReceiptStorage = new InMemoryReceiptStorage(); + InMemoryReceiptStorage inMemoryReceiptStorage = new(); - Context ctx = new Context(); + Context ctx = new(); ctx.BlockTree = Build.A.BlockTree().OfChainLength(1024).TestObject; - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); Response responseOptions = Response.AllCorrect; - SyncPeerMock syncPeer = new SyncPeerMock(2048 + 1, false, responseOptions); - PeerInfo peerInfo = new PeerInfo(syncPeer); + SyncPeerMock syncPeer = new(2048 + 1, false, responseOptions); + PeerInfo peerInfo = new(syncPeer); - var block1024 = Build.A.Block.WithParent(ctx.BlockTree.Head).WithDifficulty(ctx.BlockTree.Head.Difficulty + 1).TestObject; - var block1025 = Build.A.Block.WithParent(block1024).WithDifficulty(block1024.Difficulty + 1).TestObject; - var block1026 = Build.A.Block.WithParent(block1025).WithDifficulty(block1025.Difficulty + 1).TestObject; + Block block1024 = Build.A.Block.WithParent(ctx.BlockTree.Head).WithDifficulty(ctx.BlockTree.Head.Difficulty + 1).TestObject; + Block block1025 = Build.A.Block.WithParent(block1024).WithDifficulty(block1024.Difficulty + 1).TestObject; + Block block1026 = Build.A.Block.WithParent(block1025).WithDifficulty(block1025.Difficulty + 1).TestObject; ctx.BlockTree.SuggestBlock(block1024); ctx.BlockTree.SuggestBlock(block1025); ctx.BlockTree.SuggestBlock(block1026); @@ -179,16 +181,16 @@ public async Task Ancestor_lookup_headers() [Test] public void Ancestor_failure() { - InMemoryReceiptStorage memReceiptStorage = new InMemoryReceiptStorage(); + InMemoryReceiptStorage memReceiptStorage = new(); - Context ctx = new Context(); + Context ctx = new(); ctx.BlockTree = Build.A.BlockTree().OfChainLength(2048 + 1).TestObject; - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, memReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, memReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); Response blockResponseOptions = Response.AllCorrect; - SyncPeerMock syncPeer = new SyncPeerMock(2072 + 1, true, blockResponseOptions); + SyncPeerMock syncPeer = new(2072 + 1, true, blockResponseOptions); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); Assert.ThrowsAsync(() => downloader.DownloadHeaders(peerInfo, new BlocksRequest(), CancellationToken.None)); ctx.BlockTree.BestSuggestedHeader.Number.Should().Be(2048); @@ -197,16 +199,16 @@ public void Ancestor_failure() [Test] public void Ancestor_failure_blocks() { - InMemoryReceiptStorage inMemoryReceiptStorage = new InMemoryReceiptStorage(); + InMemoryReceiptStorage inMemoryReceiptStorage = new(); - Context ctx = new Context(); + Context ctx = new(); ctx.BlockTree = Build.A.BlockTree().OfChainLength(2048 + 1).TestObject; - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); Response responseOptions = Response.AllCorrect; - SyncPeerMock syncPeer = new SyncPeerMock(2072 + 1, true, responseOptions); + SyncPeerMock syncPeer = new(2072 + 1, true, responseOptions); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); Assert.ThrowsAsync(() => downloader.DownloadBlocks(peerInfo, new BlocksRequest(), CancellationToken.None)); ctx.BlockTree.BestSuggestedHeader.Number.Should().Be(2048); @@ -217,8 +219,8 @@ public void Ancestor_failure_blocks() [TestCase(0)] public async Task Can_sync_with_peer_when_it_times_out_on_full_batch(int threshold) { - Context ctx = new Context(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = Substitute.For(); syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) @@ -230,7 +232,7 @@ public async Task Can_sync_with_peer_when_it_times_out_on_full_batch(int thresho syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); syncPeer.HeadNumber.Returns(SyncBatchSize.Max * 2 + threshold); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, threshold), CancellationToken.None).ContinueWith(t => { }); await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, threshold), CancellationToken.None); @@ -246,8 +248,8 @@ public async Task Can_sync_with_peer_when_it_times_out_on_full_batch(int thresho [Test] public async Task Headers_already_known() { - Context ctx = new Context(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = Substitute.For(); syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) @@ -256,7 +258,7 @@ public async Task Headers_already_known() syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.AllKnown)); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); syncPeer.HeadNumber.Returns(64); await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None) @@ -271,8 +273,8 @@ public async Task Headers_already_known() [TestCase(65L)] public async Task Peer_sends_just_one_item_when_advertising_more_blocks(long headNumber) { - Context ctx = new Context(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = Substitute.For(); syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) @@ -281,7 +283,7 @@ public async Task Peer_sends_just_one_item_when_advertising_more_blocks(long hea syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.JustFirst)); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); syncPeer.HeadNumber.Returns(headNumber); @@ -295,8 +297,8 @@ public async Task Peer_sends_just_one_item_when_advertising_more_blocks(long hea [TestCase(65L)] public async Task Peer_sends_just_one_item_when_advertising_more_blocks_but_no_bodies(long headNumber) { - Context ctx = new Context(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = Substitute.For(); syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) @@ -305,7 +307,7 @@ public async Task Peer_sends_just_one_item_when_advertising_more_blocks_but_no_b syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect | Response.JustFirst)); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); syncPeer.HeadNumber.Returns(headNumber); syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); @@ -318,8 +320,8 @@ public async Task Peer_sends_just_one_item_when_advertising_more_blocks_but_no_b [Test] public async Task Throws_on_null_best_peer() { - Context ctx = new Context(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); Task task1 = downloader.DownloadHeaders(null, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); await task1.ContinueWith(t => Assert.True(t.IsFaulted)); @@ -330,16 +332,16 @@ public async Task Throws_on_null_best_peer() [Test] public async Task Throws_on_inconsistent_batch() { - Context ctx = new Context(); + Context ctx = new(); ISyncPeer syncPeer = Substitute.For(); syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect ^ Response.Consistent)); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); syncPeer.HeadNumber.Returns(1024); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); await task.ContinueWith(t => Assert.True(t.IsFaulted)); } @@ -347,15 +349,15 @@ public async Task Throws_on_inconsistent_batch() [Test] public async Task Throws_on_invalid_seal() { - Context ctx = new Context(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Invalid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Invalid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = Substitute.For(); syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect)); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); syncPeer.HeadNumber.Returns(1000); Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); @@ -365,15 +367,15 @@ public async Task Throws_on_invalid_seal() [Test] public async Task Throws_on_invalid_header() { - Context ctx = new Context(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Invalid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Invalid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = Substitute.For(); syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) .Returns(ci => ctx.ResponseBuilder.BuildHeaderResponse(ci.ArgAt(0), ci.ArgAt(1), Response.AllCorrect)); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); syncPeer.HeadNumber.Returns(1000); Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); @@ -432,8 +434,8 @@ public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, B [Ignore("Fails OneLoggerLogManager Travis only")] public async Task Can_cancel_seal_validation() { - Context ctx = new Context(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, new SlowSealValidator(), NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, new SlowSealValidator(), NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = Substitute.For(); syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) @@ -442,11 +444,11 @@ public async Task Can_cancel_seal_validation() syncPeer.GetBlockBodies(Arg.Any>(), Arg.Any()) .Returns(ci => ctx.ResponseBuilder.BuildBlocksResponse(ci.ArgAt>(0), Response.AllCorrect)); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); syncPeer.HeadNumber.Returns(1000); - CancellationTokenSource cancellation = new CancellationTokenSource(); + CancellationTokenSource cancellation = new(); cancellation.CancelAfter(1000); Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), cancellation.Token); await task.ContinueWith(t => Assert.True(t.IsCanceled, $"headers {t.Status}")); @@ -462,8 +464,8 @@ public async Task Can_cancel_seal_validation() [Test, MaxTime(7000)] public async Task Can_cancel_adding_headers() { - Context ctx = new Context(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, new SlowHeaderValidator(), Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, new SlowHeaderValidator(), Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = Substitute.For(); syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) @@ -475,9 +477,9 @@ public async Task Can_cancel_adding_headers() syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); syncPeer.HeadNumber.Returns(1000); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); - CancellationTokenSource cancellation = new CancellationTokenSource(); + CancellationTokenSource cancellation = new(); cancellation.CancelAfter(1000); Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), cancellation.Token); await task.ContinueWith(t => Assert.True(t.IsCanceled, "headers")); @@ -489,6 +491,31 @@ public async Task Can_cancel_adding_headers() task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), cancellation.Token); await task.ContinueWith(t => Assert.True(t.IsCanceled, "blocks")); } + + [Test] + public async Task Validate_always_the_last_seal_and_random_seal_in_the_package() + { + ISealValidator sealValidator = Substitute.For(); + sealValidator.ValidateSeal(Arg.Any(), Arg.Any()).Returns(true); + Context ctx = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, sealValidator, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); + + BlockHeader[] blockHeaders = await ctx.ResponseBuilder.BuildHeaderResponse(0, 512, Response.AllCorrect); + ISyncPeer syncPeer = Substitute.For(); + syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); + syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(blockHeaders); + + PeerInfo peerInfo = new(syncPeer); + syncPeer.HeadNumber.Returns(511); + + Task task = downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); + await task; + + sealValidator.Received(2).ValidateSeal(Arg.Any(), true); + sealValidator.Received(510).ValidateSeal(Arg.Any(), false); + sealValidator.Received().ValidateSeal(blockHeaders[^1], true); + } private class ThrowingPeer : ISyncPeer { @@ -567,11 +594,11 @@ public bool TryGetSatelliteProtocol(string protocol, out T protocolHandler) w [Test] public async Task Faults_on_get_headers_faulting() { - Context ctx = new Context(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, new InMemoryReceiptStorage(), RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = new ThrowingPeer(1000, UInt256.MaxValue); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None) .ContinueWith(t => Assert.True(t.IsFaulted)); @@ -580,9 +607,9 @@ public async Task Faults_on_get_headers_faulting() [Test] public async Task Throws_on_block_task_exception() { - Context ctx = new Context(); - InMemoryReceiptStorage inMemoryReceiptStorage = new InMemoryReceiptStorage(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + InMemoryReceiptStorage inMemoryReceiptStorage = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = Substitute.For(); syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); @@ -596,7 +623,7 @@ public async Task Throws_on_block_task_exception() syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions)); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); syncPeer.HeadNumber.Returns(1); await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); @@ -611,10 +638,10 @@ public async Task Throws_on_block_task_exception() [TestCase(DownloaderOptions.Process, false)] public async Task Throws_on_receipt_task_exception_when_downloading_receipts(int options, bool shouldThrow) { - Context ctx = new Context(); + Context ctx = new(); DownloaderOptions downloaderOptions = (DownloaderOptions) options; - InMemoryReceiptStorage inMemoryReceiptStorage = new InMemoryReceiptStorage(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); + InMemoryReceiptStorage inMemoryReceiptStorage = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = Substitute.For(); syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); @@ -630,7 +657,7 @@ public async Task Throws_on_receipt_task_exception_when_downloading_receipts(int syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) .Returns(Task.FromException(new TimeoutException())); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); syncPeer.HeadNumber.Returns(1); await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, 0), CancellationToken.None); @@ -653,11 +680,11 @@ public async Task Throws_on_receipt_task_exception_when_downloading_receipts(int [TestCase(DownloaderOptions.Process, false)] public async Task Throws_on_null_receipt_downloaded(int options, bool shouldThrow) { - Context ctx = new Context(); + Context ctx = new(); DownloaderOptions downloaderOptions = (DownloaderOptions)options; bool withReceipts = downloaderOptions == DownloaderOptions.WithReceipts; - InMemoryReceiptStorage receiptStorage = new InMemoryReceiptStorage(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, receiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); + InMemoryReceiptStorage receiptStorage = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, receiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); Response responseOptions = Response.AllCorrect; if (withReceipts) @@ -670,7 +697,7 @@ public async Task Throws_on_null_receipt_downloaded(int options, bool shouldThro // normally chain length should be head number + 1 so here we setup a slightly shorter chain which // will only be fixed slightly later long chainLength = headNumber + 1; - SyncPeerMock syncPeerInternal = new SyncPeerMock(chainLength, withReceipts, responseOptions); + SyncPeerMock syncPeerInternal = new(chainLength, withReceipts, responseOptions); ISyncPeer syncPeer = Substitute.For(); syncPeer.GetBlockHeaders(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) .Returns(ci => syncPeerInternal.GetBlockHeaders(ci.ArgAt(0), ci.ArgAt(1), ci.ArgAt(2), ci.ArgAt(3))); @@ -690,7 +717,7 @@ public async Task Throws_on_null_receipt_downloaded(int options, bool shouldThro syncPeer.HeadHash.Returns(ci => syncPeerInternal.HeadHash); syncPeer.HeadNumber.Returns(ci => syncPeerInternal.HeadNumber); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); int threshold = 2; await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.None, threshold), CancellationToken.None); @@ -713,9 +740,9 @@ public async Task Throws_on_null_receipt_downloaded(int options, bool shouldThro [TestCase(0)] public async Task Throws_on_block_bodies_count_higher_than_receipts_list_count(int threshold) { - Context ctx = new Context(); - InMemoryReceiptStorage inMemoryReceiptStorage = new InMemoryReceiptStorage(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + InMemoryReceiptStorage inMemoryReceiptStorage = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = Substitute.For(); syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); @@ -731,7 +758,7 @@ public async Task Throws_on_block_bodies_count_higher_than_receipts_list_count(i syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions).Result.Skip(1).ToArray()); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); syncPeer.HeadNumber.Returns(1); await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, threshold), CancellationToken.None); @@ -745,9 +772,9 @@ public async Task Throws_on_block_bodies_count_higher_than_receipts_list_count(i [TestCase(1)] public async Task Does_throw_on_transaction_count_different_than_receipts_count_in_block(int threshold) { - Context ctx = new Context(); - InMemoryReceiptStorage inMemoryReceiptStorage = new InMemoryReceiptStorage(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + InMemoryReceiptStorage inMemoryReceiptStorage = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = Substitute.For(); syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); @@ -763,7 +790,7 @@ public async Task Does_throw_on_transaction_count_different_than_receipts_count_ .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions) .Result.Select(r => r == null || r.Length == 0 ? r : r.Skip(1).ToArray()).ToArray()); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); syncPeer.HeadNumber.Returns(1); await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.None, threshold), CancellationToken.None); @@ -777,9 +804,9 @@ public async Task Does_throw_on_transaction_count_different_than_receipts_count_ [TestCase(1)] public async Task Throws_on_incorrect_receipts_root(int threshold) { - Context ctx = new Context(); - InMemoryReceiptStorage inMemoryReceiptStorage = new InMemoryReceiptStorage(); - BlockDownloader downloader = new BlockDownloader(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); + Context ctx = new(); + InMemoryReceiptStorage inMemoryReceiptStorage = new(); + BlockDownloader downloader = new(ctx.Feed, ctx.PeerPool, ctx.BlockTree, Always.Valid, Always.Valid, NullSyncReport.Instance, inMemoryReceiptStorage, RopstenSpecProvider.Instance, LimboLogs.Instance); ISyncPeer syncPeer = Substitute.For(); syncPeer.TotalDifficulty.Returns(UInt256.MaxValue); @@ -795,7 +822,7 @@ public async Task Throws_on_incorrect_receipts_root(int threshold) syncPeer.GetReceipts(Arg.Any>(), Arg.Any()) .Returns(ci => ctx.ResponseBuilder.BuildReceiptsResponse(ci.ArgAt>(0), Response.AllCorrect | Response.WithTransactions).Result); - PeerInfo peerInfo = new PeerInfo(syncPeer); + PeerInfo peerInfo = new(syncPeer); syncPeer.HeadNumber.Returns(1); await downloader.DownloadHeaders(peerInfo, new BlocksRequest(DownloaderOptions.WithBodies, threshold), CancellationToken.None); @@ -830,7 +857,7 @@ private class Context public Context() { Block genesis = Build.A.Block.Genesis.TestObject; - MemDb blockInfoDb = new MemDb(); + MemDb blockInfoDb = new(); BlockTree = new BlockTree(new MemDb(), new MemDb(), blockInfoDb, new ChainLevelInfoRepository(blockInfoDb), MainnetSpecProvider.Instance, NullBloomStorage.Instance, LimboLogs.Instance); BlockTree.SuggestBlock(genesis); @@ -840,10 +867,10 @@ public Context() PeerPool = Substitute.For(); Feed = Substitute.For>(); - var stateDb = new MemDb(); + MemDb stateDb = new MemDb(); - SyncConfig syncConfig = new SyncConfig(); - SyncProgressResolver syncProgressResolver = new SyncProgressResolver( + SyncConfig syncConfig = new(); + SyncProgressResolver syncProgressResolver = new( BlockTree, NullReceiptStorage.Instance, stateDb, @@ -861,9 +888,9 @@ public Context() private class SyncPeerMock : ISyncPeer { private readonly bool _withReceipts; - private readonly BlockHeadersMessageSerializer _headersSerializer = new BlockHeadersMessageSerializer(); - private readonly BlockBodiesMessageSerializer _bodiesSerializer = new BlockBodiesMessageSerializer(); - private readonly ReceiptsMessageSerializer _receiptsSerializer = new ReceiptsMessageSerializer(RopstenSpecProvider.Instance); + private readonly BlockHeadersMessageSerializer _headersSerializer = new(); + private readonly BlockBodiesMessageSerializer _bodiesSerializer = new(); + private readonly ReceiptsMessageSerializer _receiptsSerializer = new(RopstenSpecProvider.Instance); private IDb _blockInfoDb = new MemDb(); public BlockTree BlockTree { get; private set; } @@ -881,7 +908,7 @@ public SyncPeerMock(long chainLength, bool withReceipts, Response flags) private void BuildTree(long chainLength, bool withReceipts) { _receiptStorage = new InMemoryReceiptStorage(); - var builder = Build.A.BlockTree(); + BlockTreeBuilder builder = Build.A.BlockTree(); if (withReceipts) { builder = builder.WithTransactions(_receiptStorage, MainnetSpecProvider.Instance); @@ -926,7 +953,7 @@ public async Task GetBlockBodies(IList blockHashes, Cancell headers[i++] = BlockTree.FindBlock(blockHash, BlockTreeLookupOptions.None).Body; } - BlockBodiesMessage message = new BlockBodiesMessage(headers); + BlockBodiesMessage message = new(headers); byte[] messageSerialized = _bodiesSerializer.Serialize(message); return await Task.FromResult(_bodiesSerializer.Deserialize(messageSerialized).Bodies); } @@ -955,7 +982,7 @@ public async Task GetBlockHeaders(long number, int maxBlocks, int headers[i] = BlockTree.FindHeader(number + i, BlockTreeLookupOptions.None); } - BlockHeadersMessage message = new BlockHeadersMessage(headers); + BlockHeadersMessage message = new(headers); byte[] messageSerialized = _headersSerializer.Serialize(message); return await Task.FromResult(_headersSerializer.Deserialize(messageSerialized).BlockHeaders); } @@ -988,7 +1015,7 @@ public async Task GetReceipts(IList blockHash, Cancellati receipts[i++] = blockReceipts; } - ReceiptsMessage message = new ReceiptsMessage(receipts); + ReceiptsMessage message = new(receipts); byte[] messageSerialized = _receiptsSerializer.Serialize(message); return await Task.FromResult(_receiptsSerializer.Deserialize(messageSerialized).TxReceipts); } @@ -1059,17 +1086,17 @@ public async Task BuildHeaderResponse(long startNumber, int numbe _headers[header.Hash] = header; } - BlockHeadersMessage message = new BlockHeadersMessage(headers); + BlockHeadersMessage message = new(headers); byte[] messageSerialized = _headersSerializer.Serialize(message); return await Task.FromResult(_headersSerializer.Deserialize(messageSerialized).BlockHeaders); } - private readonly BlockHeadersMessageSerializer _headersSerializer = new BlockHeadersMessageSerializer(); - private readonly BlockBodiesMessageSerializer _bodiesSerializer = new BlockBodiesMessageSerializer(); - private readonly ReceiptsMessageSerializer _receiptsSerializer = new ReceiptsMessageSerializer(RopstenSpecProvider.Instance); + private readonly BlockHeadersMessageSerializer _headersSerializer = new(); + private readonly BlockBodiesMessageSerializer _bodiesSerializer = new(); + private readonly ReceiptsMessageSerializer _receiptsSerializer = new(RopstenSpecProvider.Instance); - private Dictionary _headers = new Dictionary(); - private Dictionary _bodies = new Dictionary(); + private Dictionary _headers = new(); + private Dictionary _bodies = new(); public async Task BuildBlocksResponse(IList blockHashes, Response flags) { @@ -1127,7 +1154,7 @@ public async Task BuildBlocksResponse(IList blockHashes, Re } } - BlockBodiesMessage message = new BlockBodiesMessage(blockBodies); + BlockBodiesMessage message = new(blockBodies); byte[] messageSerialized = _bodiesSerializer.Serialize(message); return await Task.FromResult(_bodiesSerializer.Deserialize(messageSerialized).Bodies); } @@ -1152,7 +1179,7 @@ public async Task BuildReceiptsResponse(IList blockHashes : new ReceiptTrie(MainnetSpecProvider.Instance.GetSpec(_headers[blockHashes[i]].Number), receipts[i]).RootHash; } - ReceiptsMessage message = new ReceiptsMessage(receipts); + ReceiptsMessage message = new(receipts); byte[] messageSerialized = _receiptsSerializer.Serialize(message); return await Task.FromResult(_receiptsSerializer.Deserialize(messageSerialized).TxReceipts); } diff --git a/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs b/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs index 631b44bc85e..67332005567 100644 --- a/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs +++ b/src/Nethermind/Nethermind.Synchronization/Blocks/BlockDownloader.cs @@ -48,6 +48,7 @@ internal class BlockDownloader : SyncDispatcher private readonly IReceiptsRecovery _receiptsRecovery; private readonly ISpecProvider _specProvider; private readonly ILogger _logger; + private readonly Random _rnd = new(); private bool _cancelDueToBetterPeer; private AllocationWithCancellation _allocationWithCancellation; @@ -494,6 +495,7 @@ private void ValidateSeals(BlockHeader?[] headers, CancellationToken cancellatio { if (_logger.IsTrace) _logger.Trace("Starting seal validation"); ConcurrentQueue exceptions = new(); + int randomNumberForValidation = _rnd.Next(Math.Max(0, headers.Length - 2)); Parallel.For(0, headers.Length, (i, state) => { if (cancellation.IsCancellationRequested) @@ -511,7 +513,8 @@ private void ValidateSeals(BlockHeader?[] headers, CancellationToken cancellatio try { - if (!_sealValidator.ValidateSeal(header, false)) + bool forceValidation = i == headers.Length - 1 || i == randomNumberForValidation; + if (!_sealValidator.ValidateSeal(header, forceValidation)) { if (_logger.IsTrace) _logger.Trace("One of the seals is invalid"); throw new EthSyncException("Peer sent a block with an invalid seal");