public Task <SyncPeerAllocation> BorrowAsync(IPeerSelectionStrategy peerSelectionStrategy, string description = "", int timeoutMilliseconds = 0) { SyncPeerAllocation allocation = new SyncPeerAllocation(peerSelectionStrategy); allocation.AllocateBestPeer(UsefulPeers.Where(p => !p.IsAllocated), new NodeStatsManager(new StatsConfig(), LimboLogs.Instance), SyncPeerTree, description); return(Task.FromResult(allocation)); }
public async Task Can_borrow_many() { await SetupPeers(2); SyncPeerAllocation allocation1 = await _pool.BorrowAsync(BySpeedSelectionStrategy.Fastest); SyncPeerAllocation allocation2 = await _pool.BorrowAsync(BySpeedSelectionStrategy.Fastest); Assert.AreNotSame(allocation1.Current, allocation2.Current, "first"); Assert.NotNull(allocation1.Current, "first A"); Assert.NotNull(allocation2.Current, "first B"); _pool.Free(allocation1); _pool.Free(allocation2); Assert.Null(allocation1.Current, "null A"); Assert.Null(allocation2.Current, "null B"); allocation1 = await _pool.BorrowAsync(BySpeedSelectionStrategy.Fastest); allocation2 = await _pool.BorrowAsync(BySpeedSelectionStrategy.Fastest); Assert.AreNotSame(allocation1.Current, allocation2.Current); Assert.NotNull(allocation1.Current, "second A"); Assert.NotNull(allocation2.Current, "second B"); }
private async Task ExecuteRequest(CancellationToken token, StateSyncBatch batch) { SyncPeerAllocation nodeSyncAllocation = _syncPeerPool.Borrow(BorrowOptions.DoNotReplace, "node sync"); try { ISyncPeer peer = nodeSyncAllocation?.Current?.SyncPeer; batch.AssignedPeer = nodeSyncAllocation; if (peer != null) { var hashes = batch.RequestedNodes.Select(r => r.Hash).ToArray(); Task <byte[][]> getNodeDataTask = peer.GetNodeData(hashes, token); await getNodeDataTask.ContinueWith( t => { if (t.IsCompletedSuccessfully) { batch.Responses = getNodeDataTask.Result; } } ); } (NodeDataHandlerResult Result, int NodesConsumed)result = (NodeDataHandlerResult.InvalidFormat, 0); try { result = _nodeDataFeed.HandleResponse(batch); if (result.Result == NodeDataHandlerResult.BadQuality) { _syncPeerPool.ReportBadPeer(batch.AssignedPeer); } } catch (Exception e) { if (_logger.IsError) { _logger.Error($"Error when handling response", e); } } Interlocked.Add(ref _consumedNodesCount, result.NodesConsumed); if (result.NodesConsumed == 0 && peer != null) { _syncPeerPool.ReportNoSyncProgress(nodeSyncAllocation); } } finally { if (nodeSyncAllocation != null) { // _logger.Warn($"Free {nodeSyncAllocation?.Current}"); _syncPeerPool.Free(nodeSyncAllocation); } } }
public Task <SyncPeerAllocation> Allocate(IPeerAllocationStrategy peerAllocationStrategy, AllocationContexts contexts, int timeoutMilliseconds = 0) { ISyncPeer syncPeer = Substitute.For <ISyncPeer>(); syncPeer.ClientId.Returns("Nethermind"); syncPeer.TotalDifficulty.Returns(UInt256.One); SyncPeerAllocation allocation = new SyncPeerAllocation(new PeerInfo(syncPeer), contexts); allocation.AllocateBestPeer(null, null, null); return(Task.FromResult(allocation)); }
public async Task Does_not_allocate_sleeping_peers() { var peers = await SetupPeers(3); _pool.ReportNoSyncProgress(_pool.AllPeers.First()); SyncPeerAllocation allocation1 = await _pool.BorrowAsync(BySpeedSelectionStrategy.Fastest); SyncPeerAllocation allocation2 = await _pool.BorrowAsync(BySpeedSelectionStrategy.Fastest); SyncPeerAllocation allocation3 = await _pool.BorrowAsync(BySpeedSelectionStrategy.Fastest); Assert.True(allocation1.HasPeer); Assert.True(allocation2.HasPeer); Assert.False(allocation3.HasPeer); }
public async Task Does_not_replace_with_a_worse_peer() { SetupSpeedStats(TestItem.PublicKeyA, 200); SetupSpeedStats(TestItem.PublicKeyB, 100); _pool.Start(); _pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA)); await WaitForPeersInitialization(); SyncPeerAllocation allocation = await _pool.BorrowAsync(BySpeedSelectionStrategy.Fastest); bool replaced = false; allocation.Replaced += (sender, args) => replaced = true; _pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyB)); await WaitForPeersInitialization(); Assert.False(replaced); }
public AllocationWithCancellation(SyncPeerAllocation allocation, CancellationTokenSource cancellation) { Allocation = allocation; Cancellation = cancellation; _isDisposed = false; }
public void Free(SyncPeerAllocation syncPeerAllocation) { }
private async Task ExecuteRequest(CancellationToken token, FastBlocksBatch batch) { SyncPeerAllocation nodeSyncAllocation = _syncPeerPool.Borrow(BorrowOptions.DoNotReplace | (batch.Prioritized ? BorrowOptions.None : BorrowOptions.LowPriority), "fast blocks", batch.MinNumber); foreach (PeerInfo peerInfo in _syncPeerPool.UsefulPeers) { if (peerInfo.HeadNumber < Math.Max(0, (batch.MinNumber ?? 0) - 1024)) { if (_logger.IsDebug) { _logger.Debug($"Made {peerInfo} sleep for a while - no min number satisfied"); } _syncPeerPool.ReportNoSyncProgress(peerInfo); } } try { ISyncPeer peer = nodeSyncAllocation?.Current?.SyncPeer; batch.Allocation = nodeSyncAllocation; if (peer != null) { batch.MarkSent(); switch (batch.BatchType) { case FastBlocksBatchType.Headers: { Task <BlockHeader[]> getHeadersTask = peer.GetBlockHeaders(batch.Headers.StartNumber, batch.Headers.RequestSize, 0, token); await getHeadersTask.ContinueWith( t => { if (t.IsCompletedSuccessfully) { if (batch.RequestTime > 1000) { if (_logger.IsDebug) { _logger.Debug($"{batch} - peer is slow {batch.RequestTime:F2}"); } } batch.Headers.Response = getHeadersTask.Result; ValidateHeaders(token, batch); } else { _syncPeerPool.ReportInvalid(batch.Allocation); } } ); break; } case FastBlocksBatchType.Bodies: { Task <BlockBody[]> getBodiesTask = peer.GetBlocks(batch.Bodies.Request, token); await getBodiesTask.ContinueWith( t => { if (t.IsCompletedSuccessfully) { if (batch.RequestTime > 1000) { if (_logger.IsDebug) { _logger.Debug($"{batch} - peer is slow {batch.RequestTime:F2}"); } } batch.Bodies.Response = getBodiesTask.Result; } else { _syncPeerPool.ReportInvalid(batch.Allocation); } } ); break; } case FastBlocksBatchType.Receipts: { Task <TxReceipt[][]> getReceiptsTask = peer.GetReceipts(batch.Receipts.Request, token); await getReceiptsTask.ContinueWith( t => { if (t.IsCompletedSuccessfully) { if (batch.RequestTime > 1000) { if (_logger.IsDebug) { _logger.Debug($"{batch} - peer is slow {batch.RequestTime:F2}"); } } batch.Receipts.Response = getReceiptsTask.Result; } else { _syncPeerPool.ReportInvalid(batch.Allocation); } } ); break; } default: { throw new InvalidOperationException($"{nameof(FastBlocksBatchType)} is {batch.BatchType}"); } } } (BlocksDataHandlerResult Result, int ItemsSynced)result = (BlocksDataHandlerResult.InvalidFormat, 0); try { if (batch.Bodies?.Response == null && batch.Headers?.Response == null && batch.Receipts?.Response == null) { // to avoid uncontrolled loop in case of a code error await Task.Delay(10); } result = _fastBlocksFeed.HandleResponse(batch); } catch (Exception e) { // possibly clear the response and handle empty response batch here (to avoid missing parts) if (_logger.IsError) { _logger.Error($"Error when handling response", e); } } Interlocked.Add(ref _downloadedHeaders, result.ItemsSynced); if (result.ItemsSynced == 0 && peer != null) { _syncPeerPool.ReportNoSyncProgress(nodeSyncAllocation); } } finally { if (nodeSyncAllocation != null) { _syncPeerPool.Free(nodeSyncAllocation); } } }
public void Free(SyncPeerAllocation syncPeerAllocation) { syncPeerAllocation.Cancel(); }
public void ReportWeakPeer(SyncPeerAllocation allocation) { WeakPeerReports.Enqueue(allocation.Current); }
private async Task ExecuteRequest(CancellationToken token, FastBlocksBatch batch) { SyncPeerAllocation syncPeerAllocation = batch.Allocation; try { foreach (PeerInfo usefulPeer in _syncPeerPool.UsefulPeers) { if (usefulPeer.HeadNumber < Math.Max(0, (batch.MinNumber ?? 0) - 1024)) { if (_logger.IsDebug) { _logger.Debug($"Made {usefulPeer} sleep for a while - no min number satisfied"); } _syncPeerPool.ReportNoSyncProgress(usefulPeer); } } PeerInfo peerInfo = syncPeerAllocation?.Current; ISyncPeer peer = peerInfo?.SyncPeer; if (peer != null) { batch.MarkSent(); switch (batch.BatchType) { case FastBlocksBatchType.Headers: { Task <BlockHeader[]> getHeadersTask = peer.GetBlockHeaders(batch.Headers.StartNumber, batch.Headers.RequestSize, 0, token); await getHeadersTask.ContinueWith( t => { if (t.IsCompletedSuccessfully) { if (batch.RequestTime > 1000) { if (_logger.IsDebug) { _logger.Debug($"{batch} - peer is slow {batch.RequestTime:F2}"); } } batch.Headers.Response = getHeadersTask.Result; } else { if (t.Exception.InnerExceptions.Any(e => e is TimeoutException)) { _syncPeerPool.ReportInvalid(batch.Allocation, $"headers -> timeout"); } else { _syncPeerPool.ReportInvalid(batch.Allocation, $"headers -> {t.Exception}"); } } } ); break; } case FastBlocksBatchType.Bodies: { Task <BlockBody[]> getBodiesTask = peer.GetBlockBodies(batch.Bodies.Request, token); await getBodiesTask.ContinueWith( t => { if (t.IsCompletedSuccessfully) { if (batch.RequestTime > 1000) { if (_logger.IsDebug) { _logger.Debug($"{batch} - peer is slow {batch.RequestTime:F2}"); } } batch.Bodies.Response = getBodiesTask.Result; } else { if (t.Exception.InnerExceptions.Any(e => e is TimeoutException)) { _syncPeerPool.ReportInvalid(batch.Allocation, $"bodies -> timeout"); } else { _syncPeerPool.ReportInvalid(batch.Allocation, $"bodies -> {t.Exception}"); } } } ); break; } case FastBlocksBatchType.Receipts: { Task <TxReceipt[][]> getReceiptsTask = peer.GetReceipts(batch.Receipts.Request, token); await getReceiptsTask.ContinueWith( t => { if (t.IsCompletedSuccessfully) { if (batch.RequestTime > 1000) { if (_logger.IsDebug) { _logger.Debug($"{batch} - peer is slow {batch.RequestTime:F2}"); } } batch.Receipts.Response = getReceiptsTask.Result; } else { if (t.Exception.InnerExceptions.Any(e => e is TimeoutException)) { _syncPeerPool.ReportInvalid(batch.Allocation, $"receipts -> timeout"); } else { _syncPeerPool.ReportInvalid(batch.Allocation, $"receipts -> {t.Exception}"); } } } ); break; } default: { throw new InvalidOperationException($"{nameof(FastBlocksBatchType)} is {batch.BatchType}"); } } } (BlocksDataHandlerResult Result, int ItemsSynced)result = (BlocksDataHandlerResult.InvalidFormat, 0); try { result = _fastBlocksFeed.HandleResponse(batch); } catch (Exception e) { // possibly clear the response and handle empty response batch here (to avoid missing parts) // this practically corrupts sync if (_logger.IsError) { _logger.Error($"Error when handling response", e); } } Interlocked.Add(ref _downloadedHeaders, result.ItemsSynced); if (result.ItemsSynced == 0 && peer != null) { _syncPeerPool.ReportNoSyncProgress(peerInfo); } } finally { if (syncPeerAllocation != null) { _syncPeerPool.Free(syncPeerAllocation); } } }