Example #1
0
        public ConcordionBuilder()
        {
            SpecificationLocator = new ClassNameBasedSpecificationLocator();
            Source               = null;
            Target               = null;
            CommandRegistry      = new CommandRegistry();
            DocumentParser       = new DocumentParser(CommandRegistry);
            EvaluatorFactory     = new SimpleEvaluatorFactory();
            SpecificationCommand = new SpecificationCommand();
            AssertEqualsCommand  = new AssertEqualsCommand();
            AssertTrueCommand    = new AssertTrueCommand();
            AssertFalseCommand   = new AssertFalseCommand();
            ExecuteCommand       = new ExecuteCommand();
            RunCommand           = new RunCommand();
            VerifyRowsCommand    = new VerifyRowsCommand();
            EchoCommand          = new EchoCommand();
            ExceptionRenderer    = new ExceptionRenderer();

            // Set up the commands

            CommandRegistry.Register("", "specification", SpecificationCommand);
            WithApprovedCommand(HtmlFramework.NAMESPACE_CONCORDION_2007, "run", RunCommand);
            WithApprovedCommand(HtmlFramework.NAMESPACE_CONCORDION_2007, "execute", ExecuteCommand);
            WithApprovedCommand(HtmlFramework.NAMESPACE_CONCORDION_2007, "set", new SetCommand());
            WithApprovedCommand(HtmlFramework.NAMESPACE_CONCORDION_2007, "assertEquals", AssertEqualsCommand);
            WithApprovedCommand(HtmlFramework.NAMESPACE_CONCORDION_2007, "assertTrue", AssertTrueCommand);
            WithApprovedCommand(HtmlFramework.NAMESPACE_CONCORDION_2007, "assertFalse", AssertFalseCommand);
            WithApprovedCommand(HtmlFramework.NAMESPACE_CONCORDION_2007, "verifyRows", VerifyRowsCommand);
            WithApprovedCommand(HtmlFramework.NAMESPACE_CONCORDION_2007, "echo", EchoCommand);

            // Wire up the command listeners

            var assertEqualsResultRenderer = new AssertEqualsResultRenderer();

            AssertEqualsCommand.SuccessReported += assertEqualsResultRenderer.SuccessReportedEventHandler;
            AssertEqualsCommand.FailureReported += assertEqualsResultRenderer.FailureReportedEventHandler;
            AssertTrueCommand.SuccessReported   += assertEqualsResultRenderer.SuccessReportedEventHandler;
            AssertTrueCommand.FailureReported   += assertEqualsResultRenderer.FailureReportedEventHandler;
            AssertFalseCommand.SuccessReported  += assertEqualsResultRenderer.SuccessReportedEventHandler;
            AssertFalseCommand.FailureReported  += assertEqualsResultRenderer.FailureReportedEventHandler;

            var verifyRowsCommandRenderer = new VerifyRowResultRenderer();

            VerifyRowsCommand.MissingRowFound += verifyRowsCommandRenderer.MissingRowFoundEventHandler;
            VerifyRowsCommand.SurplusRowFound += verifyRowsCommandRenderer.SurplusRowFoundEventHandler;

            var runResultRenderer = new RunResultRenderer();

            RunCommand.SuccessfulRunReported += runResultRenderer.SuccessfulRunReportedEventHandler;
            RunCommand.FailedRunReported     += runResultRenderer.FailedRunReportedEventHandler;
            RunCommand.IgnoredRunReported    += runResultRenderer.IgnoredRunReportedEventHandler;

            var documentStructureImprovementRenderer = new DocumentStructureImprovementRenderer();

            DocumentParser.DocumentParsing += documentStructureImprovementRenderer.DocumentParsingEventHandler;

            var stylesheetEmbeddingRenderer = new StylesheetEmbeddingRenderer(HtmlFramework.EMBEDDED_STYLESHEET_RESOURCE);

            DocumentParser.DocumentParsing += stylesheetEmbeddingRenderer.DocumentParsingEventHandler;
        }
 public RenderSubscriber(
     NineChroniclesNodeService nodeService,
     MySqlStore mySqlStore
     )
 {
     _blockRenderer      = nodeService.BlockRenderer;
     _actionRenderer     = nodeService.ActionRenderer;
     _exceptionRenderer  = nodeService.ExceptionRenderer;
     _nodeStatusRenderer = nodeService.NodeStatusRenderer;
     MySqlStore          = mySqlStore;
 }
Example #3
0
 public ActionEvaluationPublisher(
     BlockRenderer blockRenderer,
     ActionRenderer actionRenderer,
     ExceptionRenderer exceptionRenderer,
     NodeStatusRenderer nodeStatusRenderer,
     string host,
     int port,
     RpcContext context
     )
 {
     _blockRenderer      = blockRenderer;
     _actionRenderer     = actionRenderer;
     _exceptionRenderer  = exceptionRenderer;
     _nodeStatusRenderer = nodeStatusRenderer;
     _host    = host;
     _port    = port;
     _context = context;
 }
Example #4
0
        private static async Task RequestOverview(string aBeatmapSetPath)
        {
            try
            {
                if (State.LoadedBeatmapSetPath != aBeatmapSetPath)
                {
                    return;
                }

                string html = OverviewRenderer.Render(State.LoadedBeatmapSet);
                await SendMessage("UpdateOverview", html);
            }
            catch (Exception exception)
            {
                string html = ExceptionRenderer.Render(exception);
                await SendMessage("UpdateException", "Overview:" + html);
            }
        }
Example #5
0
        private static async Task RequestChecks(string aBeatmapSetPath)
        {
            try
            {
                List <Issue> issues = Checker.GetBeatmapSetIssues(State.LoadedBeatmapSet);
                if (State.LoadedBeatmapSetPath != aBeatmapSetPath)
                {
                    return;
                }

                string html = ChecksRenderer.Render(issues, State.LoadedBeatmapSet);
                await SendMessage("UpdateChecks", html);
            }
            catch (Exception exception)
            {
                string html = ExceptionRenderer.Render(exception);
                await SendMessage("UpdateException", "Checks:" + html);
            }
        }
Example #6
0
        public ConcordionBuilder()
        {
            BuildListeners = new List <IConcordionBuildListener>();
            SpecificationProcessingListeners = new List <ISpecificationProcessingListener>();
            ResourceToCopyMap  = new Dictionary <string, Resource>();
            ExceptionListeners = new List <IExceptionCaughtListener>();

            SpecificationLocator = new ClassNameBasedSpecificationLocator();
            Source               = null;
            Target               = null;
            CommandRegistry      = new CommandRegistry();
            DocumentParser       = new DocumentParser(CommandRegistry);
            EvaluatorFactory     = new SimpleEvaluatorFactory();
            SpecificationCommand = new SpecificationCommand();
            AssertEqualsCommand  = new AssertEqualsCommand();
            AssertTrueCommand    = new AssertTrueCommand();
            AssertFalseCommand   = new AssertFalseCommand();
            ExecuteCommand       = new ExecuteCommand();
            RunCommand           = new RunCommand();
            VerifyRowsCommand    = new VerifyRowsCommand();
            EchoCommand          = new EchoCommand();
            ExceptionRenderer    = new ExceptionRenderer();

            WithExceptionListener(ExceptionRenderer);

            // Set up the commands

            CommandRegistry.Register("", "specification", SpecificationCommand);

            // Wire up the command listeners

            var assertResultRenderer = new AssertResultRenderer();

            WithAssertEqualsListener(assertResultRenderer);
            WithAssertTrueListener(assertResultRenderer);
            WithAssertFalseListener(assertResultRenderer);
            WithVerifyRowsListener(new VerifyRowResultRenderer());
            WithRunListener(new RunResultRenderer());
            WithDocumentParsingListener(new DocumentStructureImprover());
            WithDocumentParsingListener(new MetadataCreator());
            WithEmbeddedCss(HtmlFramework.EMBEDDED_STYLESHEET_RESOURCE);
        }
Example #7
0
        private static async Task RequestSnapshots(string aBeatmapSetPath)
        {
            try
            {
                // Beatmapset null (-1) would become ambigious with any other unsubmitted map.
                if (State.LoadedBeatmapSet.beatmaps.FirstOrDefault()?.metadataSettings.beatmapSetId != null)
                {
                    Snapshotter.SnapshotBeatmapSet(State.LoadedBeatmapSet);
                }

                if (State.LoadedBeatmapSetPath != aBeatmapSetPath)
                {
                    return;
                }

                string html = SnapshotsRenderer.Render(State.LoadedBeatmapSet);
                await SendMessage("UpdateSnapshots", html);
            }
            catch (Exception exception)
            {
                string html = ExceptionRenderer.Render(exception);
                await SendMessage("UpdateException", "Snapshots:" + html);
            }
        }
        public NineChroniclesNodeService(
            PrivateKey?minerPrivateKey,
            LibplanetNodeServiceProperties <NCAction> properties,
            Progress <PreloadState>?preloadProgress = null,
            bool ignoreBootstrapFailure             = false,
            bool ignorePreloadFailure = false,
            bool strictRendering      = false,
            bool authorizedMiner      = false,
            bool isDev          = false,
            int blockInterval   = 10000,
            int reorgInterval   = 0,
            TimeSpan txLifeTime = default,
            int minerCount      = 1
            )
        {
            MinerPrivateKey = minerPrivateKey;
            Properties      = properties;

            LogEventLevel logLevel          = LogEventLevel.Debug;
            var           blockPolicySource = new BlockPolicySource(Log.Logger, logLevel);
            // BlockPolicy shared through Lib9c.
            IBlockPolicy <NCAction>?blockPolicy = null;
            // Policies for dev mode.
            IBlockPolicy <NCAction>?easyPolicy  = null;
            IBlockPolicy <NCAction>?hardPolicy  = null;
            IStagePolicy <NCAction> stagePolicy =
                txLifeTime == default
                    ? new VolatileStagePolicy <NCAction>()
                    : new VolatileStagePolicy <NCAction>(txLifeTime);

            if (isDev)
            {
                easyPolicy = new ReorgPolicy(new RewardGold(), 1);
                hardPolicy = new ReorgPolicy(new RewardGold(), 2);
            }
            else
            {
                blockPolicy = blockPolicySource.GetPolicy(properties.MinimumDifficulty, properties.MaximumTransactions);
            }

            BlockRenderer      = blockPolicySource.BlockRenderer;
            ActionRenderer     = blockPolicySource.ActionRenderer;
            ExceptionRenderer  = new ExceptionRenderer();
            NodeStatusRenderer = new NodeStatusRenderer();
            var renderers      = new List <IRenderer <NCAction> >();
            var strictRenderer = new StrictRenderer(onError: exc =>
                                                    ExceptionRenderer.RenderException(
                                                        RPCException.InvalidRenderException,
                                                        exc.Message.Split("\n")[0]
                                                        )
                                                    );

            if (Properties.Render)
            {
                renderers.Add(blockPolicySource.BlockRenderer);
                renderers.Add(blockPolicySource.LoggedActionRenderer);
            }
            else if (Properties.LogActionRenders)
            {
                renderers.Add(blockPolicySource.BlockRenderer);
                // The following "nullRenderer" does nothing.  It's just for filling
                // the LoggedActionRenderer<T>() constructor's parameter:
                IActionRenderer <NCAction> nullRenderer =
                    new AnonymousActionRenderer <NCAction>();
                renderers.Add(
                    new LoggedActionRenderer <NCAction>(
                        nullRenderer,
                        Log.Logger,
                        logLevel
                        )
                    );
            }
            else
            {
                renderers.Add(blockPolicySource.LoggedBlockRenderer);
            }

            if (strictRendering)
            {
                Log.Debug(
                    $"Strict rendering is on. Add {nameof(StrictRenderer)}.");
                renderers.Add(strictRenderer);
            }

            async Task minerLoopAction(
                BlockChain <NCAction> chain,
                Swarm <NCAction> swarm,
                PrivateKey privateKey,
                CancellationToken cancellationToken)
            {
                var miner = new Miner(chain, swarm, privateKey, authorizedMiner);

                Log.Debug("Miner called.");
                while (!cancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        long nextBlockIndex = chain.Tip.Index + 1;
                        bool authBlock      = blockPolicy is BlockPolicy bp
                                              // Copied from https://git.io/JLxNd
                                              && nextBlockIndex > 0 &&
                                              nextBlockIndex <= bp.AuthorizedMinersState?.ValidUntil &&
                                              nextBlockIndex % bp.AuthorizedMinersState?.Interval == 0;
                        if (swarm.Running && ((authorizedMiner && authBlock) || (!authorizedMiner && !authBlock)))
                        {
                            Log.Debug("Start mining.");

                            IEnumerable <Task <Block <NCAction> > > miners = Enumerable
                                                                             .Range(0, minerCount)
                                                                             .Select(_ => miner.MineBlockAsync(properties.MaximumTransactions, cancellationToken));
                            await Task.WhenAll(miners);
                        }
                        else
                        {
                            await Task.Delay(1000, cancellationToken);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, "Exception occurred.");
                    }
                }
            }

            async Task devMinerLoopAction(
                Swarm <NCAction> mainSwarm,
                Swarm <NCAction> subSwarm,
                PrivateKey privateKey,
                CancellationToken cancellationToken)
            {
                var miner = new ReorgMiner(mainSwarm, subSwarm, privateKey, reorgInterval);

                Log.Debug("Miner called.");
                while (!cancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        if (mainSwarm.Running)
                        {
                            Log.Debug("Start mining.");
                            await miner.MineBlockAsync(properties.MaximumTransactions, cancellationToken);

                            await Task.Delay(blockInterval, cancellationToken);
                        }
                        else
                        {
                            await Task.Delay(1000, cancellationToken);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, "Exception occurred.");
                    }
                }
            }

            if (isDev)
            {
                NodeService = new DevLibplanetNodeService <NCAction>(
                    Properties,
                    easyPolicy,
                    hardPolicy,
                    stagePolicy,
                    renderers,
                    devMinerLoopAction,
                    preloadProgress,
                    (code, msg) =>
                {
                    ExceptionRenderer.RenderException(code, msg);
                    Log.Error(msg);
                },
                    isPreloadStarted => { NodeStatusRenderer.PreloadStatus(isPreloadStarted); },
                    ignoreBootstrapFailure
                    );
            }
            else
            {
                NodeService = new LibplanetNodeService <NCAction>(
                    Properties,
                    blockPolicy,
                    stagePolicy,
                    renderers,
                    minerLoopAction,
                    preloadProgress,
                    (code, msg) =>
                {
                    ExceptionRenderer.RenderException(code, msg);
                    Log.Error(msg);
                },
                    isPreloadStarted =>
                {
                    NodeStatusRenderer.PreloadStatus(isPreloadStarted);
                },
                    ignoreBootstrapFailure,
                    ignorePreloadFailure
                    );
            }

            strictRenderer.BlockChain = NodeService.BlockChain ?? throw new Exception("BlockChain is null.");
            if (NodeService.BlockChain?.GetState(AuthorizedMinersState.Address) is Dictionary ams &&
                blockPolicy is BlockPolicy bp)
            {
                bp.AuthorizedMinersState = new AuthorizedMinersState(ams);
            }

            if (authorizedMiner && blockPolicy is BlockPolicy {
                AuthorizedMinersState : null
            })
Example #9
0
        public NineChroniclesNodeService(
            LibplanetNodeServiceProperties <NineChroniclesActionType> properties,
            RpcNodeServiceProperties?rpcNodeServiceProperties,
            Progress <PreloadState> preloadProgress = null,
            bool ignoreBootstrapFailure             = false,
            bool strictRendering = false,
            bool isDev           = false,
            int blockInterval    = 10000,
            int reorgInterval    = 0
            )
        {
            Properties    = properties;
            RpcProperties = rpcNodeServiceProperties;

            try
            {
                Libplanet.Crypto.CryptoConfig.CryptoBackend = new Secp256K1CryptoBackend <SHA256>();
                Log.Debug("Secp256K1CryptoBackend initialized.");
            }
            catch (Exception e)
            {
                Log.Error("Secp256K1CryptoBackend initialize failed. Use default backend. {e}", e);
            }

            var blockPolicySource = new BlockPolicySource(Log.Logger, LogEventLevel.Debug);
            // BlockPolicy shared through Lib9c.
            IBlockPolicy <PolymorphicAction <ActionBase> > blockPolicy = null;
            // Policies for dev mode.
            IBlockPolicy <PolymorphicAction <ActionBase> > easyPolicy = null;
            IBlockPolicy <PolymorphicAction <ActionBase> > hardPolicy = null;

            if (isDev)
            {
                easyPolicy = new ReorgPolicy(new RewardGold(), 1);
                hardPolicy = new ReorgPolicy(new RewardGold(), 2);
            }
            else
            {
                blockPolicy = blockPolicySource.GetPolicy(properties.MinimumDifficulty, properties.MaximumTransactions);
            }

            BlockRenderer      = blockPolicySource.BlockRenderer;
            ActionRenderer     = blockPolicySource.ActionRenderer;
            ExceptionRenderer  = new ExceptionRenderer();
            NodeStatusRenderer = new NodeStatusRenderer();
            var renderers      = new List <IRenderer <NineChroniclesActionType> >();
            var strictRenderer = new StrictRenderer(onError: exc =>
                                                    ExceptionRenderer.RenderException(
                                                        RPCException.InvalidRenderException,
                                                        exc.Message.Split("\n")[0]
                                                        )
                                                    );

            if (Properties.Render)
            {
                renderers.Add(blockPolicySource.BlockRenderer);
                renderers.Add(blockPolicySource.LoggedActionRenderer);
            }
            else
            {
                renderers.Add(blockPolicySource.LoggedBlockRenderer);
            }

            if (strictRendering)
            {
                Log.Debug(
                    $"Strict rendering is on. Add {nameof(StrictRenderer)}.");
                renderers.Add(strictRenderer);
            }

            async Task minerLoopAction(
                BlockChain <NineChroniclesActionType> chain,
                Swarm <NineChroniclesActionType> swarm,
                PrivateKey privateKey,
                CancellationToken cancellationToken)
            {
                var miner = new Miner(chain, swarm, privateKey);

                Log.Debug("Miner called.");
                while (!cancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        if (swarm.Running)
                        {
                            Log.Debug("Start mining.");
                            await miner.MineBlockAsync(properties.MaximumTransactions, cancellationToken);
                        }
                        else
                        {
                            await Task.Delay(1000, cancellationToken);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, "Exception occurred.");
                    }
                }
            }

            async Task devMinerLoopAction(
                Swarm <NineChroniclesActionType> mainSwarm,
                Swarm <NineChroniclesActionType> subSwarm,
                PrivateKey privateKey,
                CancellationToken cancellationToken)
            {
                var miner = new ReorgMiner(mainSwarm, subSwarm, privateKey, reorgInterval);

                Log.Debug("Miner called.");
                while (!cancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        if (mainSwarm.Running)
                        {
                            Log.Debug("Start mining.");
                            await miner.MineBlockAsync(properties.MaximumTransactions, cancellationToken);

                            await Task.Delay(blockInterval, cancellationToken);
                        }
                        else
                        {
                            await Task.Delay(1000, cancellationToken);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, "Exception occurred.");
                    }
                }
            }

            if (isDev)
            {
                NodeService = new DevLibplanetNodeService <NineChroniclesActionType>(
                    Properties,
                    easyPolicy,
                    hardPolicy,
                    renderers,
                    devMinerLoopAction,
                    preloadProgress,
                    (code, msg) =>
                {
                    ExceptionRenderer.RenderException(code, msg);
                    Log.Error(msg);
                },
                    isPreloadStarted => { NodeStatusRenderer.PreloadStatus(isPreloadStarted); },
                    ignoreBootstrapFailure
                    );
            }
            else
            {
                NodeService = new LibplanetNodeService <NineChroniclesActionType>(
                    Properties,
                    blockPolicy,
                    renderers,
                    minerLoopAction,
                    preloadProgress,
                    (code, msg) =>
                {
                    ExceptionRenderer.RenderException(code, msg);
                    Log.Error(msg);
                },
                    isPreloadStarted =>
                {
                    NodeStatusRenderer.PreloadStatus(isPreloadStarted);
                },
                    ignoreBootstrapFailure
                    );
            }

            strictRenderer.BlockChain = NodeService?.BlockChain ?? throw new Exception("BlockChain is null.");
            if (NodeService?.BlockChain?.GetState(AuthorizedMinersState.Address) is Dictionary ams &&
                blockPolicy is BlockPolicy bp)
            {
                bp.AuthorizedMinersState = new AuthorizedMinersState(ams);
            }
        }
Example #10
0
        public static async Task ClientMessage(string aKey, string aValue)
        {
            switch (aKey)
            {
            case "RequestDocumentation":
                try
                {
                    string html = DocumentationRenderer.Render();
                    await SendMessage("UpdateDocumentation", html);
                }
                catch (Exception exception)
                {
                    string html = ExceptionRenderer.Render(exception);
                    await SendMessage("UpdateException", "Documentation:" + html);
                }
                break;

            case "RequestOverlay":
                try
                {
                    string html = OverlayRenderer.Render(aValue);
                    await SendMessage("UpdateOverlay", html);
                }
                catch (Exception exception)
                {
                    string html = ExceptionRenderer.Render(exception);
                    await SendMessage("UpdateException", "Overlay:" + html);
                }
                break;

            case "RequestBeatmapset":
                try
                {
                    LoadBeatmapSet(aValue);

                    Func <string, Task>[] actions = new Func <string, Task>[]
                    {
                        RequestSnapshots,
                        RequestChecks,
                        RequestOverview
                    };

                    if (State.LoadedBeatmapSetPath != aValue)
                    {
                        return;
                    }

                    Parallel.ForEach(actions, anAction =>
                    {
                        anAction(aValue);
                    });
                }
                catch (Exception exception)
                {
                    string html = ExceptionRenderer.Render(exception);
                    await SendMessage("UpdateException", "Checks:" + html);
                    await SendMessage("UpdateException", "Snapshots:" + html);
                    await SendMessage("UpdateException", "Overview:" + html);
                }

                break;

            default:
                break;
            }
        }
Example #11
0
 public ConcordionBuilder WithExceptionRenderer(ExceptionRenderer exceptionRendererToAttach)
 {
     ExceptionRenderer = exceptionRendererToAttach;
     return(this);
 }
        public NineChroniclesNodeService(
            PrivateKey?minerPrivateKey,
            LibplanetNodeServiceProperties <NCAction> properties,
            IBlockPolicy <NCAction> blockPolicy,
            NetworkType networkType,
            Progress <PreloadState>?preloadProgress = null,
            bool ignoreBootstrapFailure             = false,
            bool ignorePreloadFailure = false,
            bool strictRendering      = false,
            bool authorizedMiner      = false,
            bool isDev           = false,
            int blockInterval    = 10000,
            int reorgInterval    = 0,
            TimeSpan txLifeTime  = default,
            int minerCount       = 1,
            int txQuotaPerSigner = 10
            )
        {
            MinerPrivateKey = minerPrivateKey;
            Properties      = properties;

            LogEventLevel logLevel          = LogEventLevel.Debug;
            var           blockPolicySource = new BlockPolicySource(Log.Logger, logLevel);
            // Policies for dev mode.
            IBlockPolicy <NCAction>?easyPolicy  = null;
            IBlockPolicy <NCAction>?hardPolicy  = null;
            IStagePolicy <NCAction> stagePolicy = new StagePolicy(txLifeTime, txQuotaPerSigner);

            if (isDev)
            {
                easyPolicy = new ReorgPolicy(new RewardGold(), 1);
                hardPolicy = new ReorgPolicy(new RewardGold(), 2);
            }

            BlockRenderer      = blockPolicySource.BlockRenderer;
            ActionRenderer     = blockPolicySource.ActionRenderer;
            ExceptionRenderer  = new ExceptionRenderer();
            NodeStatusRenderer = new NodeStatusRenderer();
            var renderers      = new List <IRenderer <NCAction> >();
            var strictRenderer = new StrictRenderer(onError: exc =>
                                                    ExceptionRenderer.RenderException(
                                                        RPCException.InvalidRenderException,
                                                        exc.Message.Split("\n")[0]
                                                        )
                                                    );

            if (Properties.Render)
            {
                renderers.Add(blockPolicySource.BlockRenderer);
                renderers.Add(blockPolicySource.LoggedActionRenderer);
            }
            else if (Properties.LogActionRenders)
            {
                renderers.Add(blockPolicySource.BlockRenderer);
                // The following "nullRenderer" does nothing.  It's just for filling
                // the LoggedActionRenderer<T>() constructor's parameter:
                IActionRenderer <NCAction> nullRenderer =
                    new AnonymousActionRenderer <NCAction>();
                renderers.Add(
                    new LoggedActionRenderer <NCAction>(
                        nullRenderer,
                        Log.Logger,
                        logLevel
                        )
                    );
            }
            else
            {
                renderers.Add(blockPolicySource.LoggedBlockRenderer);
            }

            if (strictRendering)
            {
                Log.Debug(
                    $"Strict rendering is on. Add {nameof(StrictRenderer)}.");
                renderers.Add(strictRenderer);
            }

            async Task minerLoopAction(
                BlockChain <NCAction> chain,
                Swarm <NCAction> swarm,
                PrivateKey privateKey,
                CancellationToken cancellationToken)
            {
                var miner = new Miner(chain, swarm, privateKey, authorizedMiner);

                Log.Debug("Miner called.");
                while (!cancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        long nextBlockIndex = chain.Tip.Index + 1;

                        if (swarm.Running)
                        {
                            Log.Debug("Start mining.");

                            if (chain.Policy is BlockPolicy bp)
                            {
                                if (bp.IsAllowedToMine(privateKey.ToAddress(), chain.Count))
                                {
                                    IEnumerable <Task <Block <NCAction> > > miners = Enumerable
                                                                                     .Range(0, minerCount)
                                                                                     .Select(_ => miner.MineBlockAsync(cancellationToken));
                                    await Task.WhenAll(miners);
                                }
                                else
                                {
                                    Log.Debug(
                                        "Miner {MinerAddress} is not allowed to mine a block with index {Index} " +
                                        "under current policy.",
                                        privateKey.ToAddress(),
                                        chain.Count);
                                    await Task.Delay(1000, cancellationToken);
                                }
                            }
                            else
                            {
                                Log.Error(
                                    "No suitable policy was found for chain {ChainId}.",
                                    chain.Id);
                                await Task.Delay(1000, cancellationToken);
                            }
                        }
                        else
                        {
                            await Task.Delay(1000, cancellationToken);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, "Exception occurred.");
                    }
                }
            }

            async Task devMinerLoopAction(
                Swarm <NCAction> mainSwarm,
                Swarm <NCAction> subSwarm,
                PrivateKey privateKey,
                CancellationToken cancellationToken)
            {
                var miner = new ReorgMiner(mainSwarm, subSwarm, privateKey, reorgInterval);

                Log.Debug("Miner called.");
                while (!cancellationToken.IsCancellationRequested)
                {
                    try
                    {
                        if (mainSwarm.Running)
                        {
                            Log.Debug("Start mining.");
                            await miner.MineBlockAsync(cancellationToken);

                            await Task.Delay(blockInterval, cancellationToken);
                        }
                        else
                        {
                            await Task.Delay(1000, cancellationToken);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex, "Exception occurred.");
                    }
                }
            }

            if (isDev)
            {
                NodeService = new DevLibplanetNodeService <NCAction>(
                    Properties,
                    easyPolicy,
                    hardPolicy,
                    stagePolicy,
                    renderers,
                    devMinerLoopAction,
                    preloadProgress,
                    (code, msg) =>
                {
                    ExceptionRenderer.RenderException(code, msg);
                    Log.Error(msg);
                },
                    isPreloadStarted => { NodeStatusRenderer.PreloadStatus(isPreloadStarted); },
                    ignoreBootstrapFailure
                    );
            }
            else
            {
                NodeService = new LibplanetNodeService <NCAction>(
                    Properties,
                    blockPolicy,
                    stagePolicy,
                    renderers,
                    minerLoopAction,
                    preloadProgress,
                    (code, msg) =>
                {
                    ExceptionRenderer.RenderException(code, msg);
                    Log.Error(msg);
                },
                    isPreloadStarted =>
                {
                    NodeStatusRenderer.PreloadStatus(isPreloadStarted);
                },
                    ignoreBootstrapFailure,
                    ignorePreloadFailure
                    );
            }

            strictRenderer.BlockChain = NodeService.BlockChain ?? throw new Exception("BlockChain is null.");
        }