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();
        }