private async Task ConsumeBlockCandidates( TimeSpan timeout, CancellationToken cancellationToken) { var checkInterval = TimeSpan.FromMilliseconds(10); while (!cancellationToken.IsCancellationRequested) { if (BlockCandidateTable.Any()) { BlockHeader tipHeader = BlockChain.Tip.Header; SortedList <long, Block <T> > blocks = BlockCandidateTable.GetCurrentRoundCandidate(tipHeader); if (!(blocks is null)) { var latest = blocks.Last(); _logger.Debug( "{MethodName} has started. Excerpt: #{BlockIndex} {BlockHash} " + "Count of {BlockCandidateTable}: {Count}", nameof(ConsumeBlockCandidates), latest.Value.Index, latest.Value.Header, nameof(BlockCandidateTable), BlockCandidateTable.Count); _ = BlockCandidateProcess( blocks, timeout, cancellationToken); BlockAppended.Set(); } } else { await Task.Delay(checkInterval, cancellationToken); continue; } BlockCandidateTable.Cleanup(IsBlockNeeded); } }
private async Task ProcessFillBlocks( TimeSpan timeout, CancellationToken cancellationToken ) { var sessionRandom = new Random(); IComparer <BlockPerception> canonComparer = BlockChain.Policy.CanonicalChainComparer; while (!cancellationToken.IsCancellationRequested) { int sessionId = sessionRandom.Next(); if (!(BlockDemand is { } blockDemand)) { await Task.Delay(1, cancellationToken); continue; } BoundPeer peer = blockDemand.Peer; try { if (canonComparer.Compare( BlockChain.PerceiveBlock(BlockDemand?.Header), BlockChain.PerceiveBlock(BlockChain.Tip) ) <= 0) { using (await _blockSyncMutex.LockAsync(cancellationToken)) { BlockDemand = null; continue; } } var hash = new BlockHash(blockDemand.Header.Hash); const string startLogMsg = "{SessionId}: Got a new " + nameof(BlockDemand) + " from {Peer}; started " + "to fetch the block #{BlockIndex} {BlockHash}..."; _logger.Debug(startLogMsg, sessionId, peer, blockDemand.Header.Index, hash); await SyncPreviousBlocksAsync( blockChain : BlockChain, peer : peer, stop : hash, progress : null, timeout : timeout, totalBlockCount : 0, logSessionId : sessionId, cancellationToken : cancellationToken ); _logger.Debug( "{SessionId}: Synced block(s) from {Peer}; broadcast them to neighbors...", sessionId, peer ); // FIXME: Clean up events BlockReceived.Set(); BlockAppended.Set(); BroadcastBlock(peer.Address, BlockChain.Tip); ProcessFillBlocksFinished.Set(); } catch (TimeoutException) { const string msg = "{SessionId}: Timeout occurred during " + nameof(ProcessFillBlocks) + "() from {Peer}."; _logger.Debug(msg, sessionId, peer); } catch (InvalidBlockIndexException ibie) { const string msg = "{SessionId}: " + nameof(InvalidBlockIndexException) + " occurred during " + nameof(ProcessFillBlocks) + "() from {Peer}: {Exception}"; _logger.Warning(ibie, msg, sessionId, peer, ibie); } catch (Exception e) { const string msg = "{SessionId}: Unexpected exception occurred during " + nameof(ProcessFillBlocks) + "() from {Peer}: {Exception}"; _logger.Error(e, msg, sessionId, peer, e); } finally { using (await _blockSyncMutex.LockAsync(cancellationToken)) { const string msg = "{SessionId}: " + nameof(ProcessFillBlocks) + "() finished."; _logger.Debug(msg, sessionId); if (BlockDemand.Equals(blockDemand)) { const string resetMsg = "{SessionId}: Reset " + nameof(BlockDemand) + "..."; _logger.Debug(resetMsg, sessionId); BlockDemand = null; } } } } }