public ConsensusStats(CoinViewStack stack, CoinView coinView, ConsensusLoop consensusLoop, ChainBehavior.ChainState chainState, ConcurrentChain chain, IConnectionManager connectionManager) { stack = new CoinViewStack(coinView); this.cache = stack.Find <CachedCoinView>(); this.dbreeze = stack.Find <DBreezeCoinView>(); this.bottom = stack.Bottom; this.consensusLoop = consensusLoop; this.lookaheadPuller = this.consensusLoop.Puller as LookaheadBlockPuller; this.lastSnapshot = consensusLoop.Validator.PerformanceCounter.Snapshot(); this.lastSnapshot2 = this.dbreeze?.PerformanceCounter.Snapshot(); this.lastSnapshot3 = this.cache?.PerformanceCounter.Snapshot(); this.chainState = chainState; this.chain = chain; this.connectionManager = connectionManager; }
private void RunLoop() { try { var stack = new CoinViewStack(this.coinView); var cache = stack.Find <CachedCoinView>(); var stats = new ConsensusStats(stack, this.coinView, this.consensusLoop, this.chainState, this.chain, this.connectionManager); var cancellationToken = this.nodeLifetime.ApplicationStopping; ChainedBlock lastTip = this.consensusLoop.Tip; foreach (var block in this.consensusLoop.Execute(cancellationToken)) { if (this.consensusLoop.Tip.FindFork(lastTip) != lastTip) { Logs.FullNode.LogInformation("Reorg detected, rewinding from " + lastTip.Height + " (" + lastTip.HashBlock + ") to " + this.consensusLoop.Tip.Height + " (" + this.consensusLoop.Tip.HashBlock + ")"); } lastTip = this.consensusLoop.Tip; cancellationToken.ThrowIfCancellationRequested(); if (block.Error != null) { Logs.FullNode.LogError("Block rejected: " + block.Error.Message); //Pull again this.consensusLoop.Puller.SetLocation(this.consensusLoop.Tip); if (block.Error == ConsensusErrors.BadWitnessNonceSize) { Logs.FullNode.LogInformation("You probably need witness information, activating witness requirement for peers."); this.connectionManager.AddDiscoveredNodesRequirement(NodeServices.NODE_WITNESS); this.consensusLoop.Puller.RequestOptions(TransactionOptions.Witness); continue; } //Set the PoW chain back to ConsensusLoop.Tip this.chain.SetTip(this.consensusLoop.Tip); //Since ChainBehavior check PoW, MarkBlockInvalid can't be spammed Logs.FullNode.LogError("Marking block as invalid"); this.chainState.MarkBlockInvalid(block.Block.GetHash()); } if (block.Error == null) { this.chainState.HighestValidatedPoW = this.consensusLoop.Tip; if (this.chain.Tip.HashBlock == block.ChainedBlock?.HashBlock) { var unused = cache.FlushAsync(); } this.signals.Blocks.Broadcast(block.Block); } // TODO: replace this with a signalling object if (stats.CanLog) { stats.Log(); } } } catch (Exception ex) { if (ex is OperationCanceledException) { if (this.nodeLifetime.ApplicationStopping.IsCancellationRequested) { return; } } // TODO Need to revisit unhandled exceptions in a way that any process can signal an exception has been // thrown so that the node and all the disposables can stop gracefully. Logs.Consensus.LogCritical(new EventId(0), ex, "Consensus loop unhandled exception (Tip:" + this.consensusLoop.Tip?.Height + ")"); throw; } }