public override void Start() { this.dBreezeCoinView.Initialize().GetAwaiter().GetResult(); var cache = this.coinView as CachedCoinView; if (cache != null) { cache.MaxItems = this.nodeSettings.Cache.MaxItems; } this.consensusLoop.Initialize(); this.chainState.HighestValidatedPoW = this.consensusLoop.Tip; this.connectionManager.Parameters.TemplateBehaviors.Add(new BlockPuller.BlockPullerBehavior(blockPuller)); var flags = this.consensusLoop.GetFlags(); if (flags.ScriptFlags.HasFlag(ScriptVerify.Witness)) { connectionManager.AddDiscoveredNodesRequirement(NodeServices.NODE_WITNESS); } this.stakeChain?.Load().GetAwaiter().GetResult(); new Thread(RunLoop) { Name = "Consensus Loop" }.Start(); }
void RunLoop() { try { var stack = new CoinViewStack(CoinView); var cache = stack.Find <CachedCoinView>(); var stats = new ConsensusStats(this, stack); var cancellationToken = this.GlobalCancellation.Cancellation.Token; ChainedBlock lastTip = ConsensusLoop.Tip; foreach (var block in ConsensusLoop.Execute(cancellationToken)) { bool reorg = false; if (ConsensusLoop.Tip.FindFork(lastTip) != lastTip) { reorg = true; Logs.FullNode.LogInformation("Reorg detected, rewinding from " + lastTip.Height + " (" + lastTip.HashBlock + ") to " + ConsensusLoop.Tip.Height + " (" + ConsensusLoop.Tip.HashBlock + ")"); } lastTip = ConsensusLoop.Tip; cancellationToken.ThrowIfCancellationRequested(); if (block.Error != null) { Logs.FullNode.LogError("Block rejected: " + block.Error.Message); //Pull again ConsensusLoop.Puller.SetLocation(ConsensusLoop.Tip); if (block.Error == ConsensusErrors.BadWitnessNonceSize) { Logs.FullNode.LogInformation("You probably need witness information, activating witness requirement for peers."); ConnectionManager.AddDiscoveredNodesRequirement(NodeServices.NODE_WITNESS); ConsensusLoop.Puller.RequestOptions(TransactionOptions.Witness); continue; } //Set the PoW chain back to ConsensusLoop.Tip Chain.SetTip(ConsensusLoop.Tip); //Since ChainBehavior check PoW, MarkBlockInvalid can't be spammed Logs.FullNode.LogError("Marking block as invalid"); _ChainBehaviorState.MarkBlockInvalid(block.ChainedBlock.HashBlock); } if (!reorg && block.Error == null) { _ChainBehaviorState.HighestValidatedPoW = ConsensusLoop.Tip; if (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) //TODO: Barbaric clean exit { if (ex is OperationCanceledException) { if (this.GlobalCancellation.Cancellation.IsCancellationRequested) { return; } } if (!IsDisposed) { Logs.FullNode.LogCritical(new EventId(0), ex, "Consensus loop unhandled exception (Tip:" + ConsensusLoop.Tip?.Height + ")"); _UncatchedException = ex; Dispose(); } } }
public void Start() { if (IsDisposed) { throw new ObjectDisposedException("FullNode"); } _IsStarted.Reset(); // start all the features defined this.StartFeatures(); // == RPC == // todo: add an RPC feature if (_Settings.RPC != null) { RPCHost = new WebHostBuilder() .UseKestrel() .ForFullNode(this) .UseUrls(_Settings.RPC.GetUrls()) .UseIISIntegration() .UseStartup <RPC.Startup>() .Build(); RPCHost.Start(); _Resources.Add(RPCHost); Logs.RPC.LogInformation("RPC Server listening on: " + Environment.NewLine + String.Join(Environment.NewLine, _Settings.RPC.GetUrls())); } // === Consensus === var coinviewdb = this.Services.ServiceProvider.GetService <DBreezeCoinView>(); // DBreezeCoinView will be in the constructor of a feature coinviewdb.Initialize(this.Network.GetGenesis()).GetAwaiter().GetResult(); var blockPuller = new LookaheadBlockPuller(Chain, ConnectionManager.ConnectedNodes); ConnectionManager.Parameters.TemplateBehaviors.Add(new BlockPuller.BlockPullerBehavior(blockPuller)); var consensusValidator = this.Services.ServiceProvider.GetService <ConsensusValidator>(); // new ConsensusValidator(Network.Consensus); ConsensusLoop = new ConsensusLoop(consensusValidator, Chain, CoinView, blockPuller); this._ChainBehaviorState.HighestValidatedPoW = ConsensusLoop.Tip; // === Miner === this.Miner = new Mining(this, this.DateTimeProvider); var flags = ConsensusLoop.GetFlags(); if (flags.ScriptFlags.HasFlag(ScriptVerify.Witness)) { ConnectionManager.AddDiscoveredNodesRequirement(NodeServices.NODE_WITNESS); } // add disposables (TODO: move this to the consensus feature) this.Resources.Add(coinviewdb); _ChainBehaviorState.HighestValidatedPoW = ConsensusLoop.Tip; ConnectionManager.Start(); new Thread(RunLoop) { Name = "Consensus Loop" }.Start(); _IsStarted.Set(); this.StartPeriodicLog(); }