public PreloadStateType()
 {
     Field <NonNullGraphType <LongGraphType> >(name: "currentPhase", resolve: context => context.Source.CurrentPhase);
     Field <NonNullGraphType <LongGraphType> >(name: "totalPhase", resolve: context => PreloadState.TotalPhase);
     Field <NonNullGraphType <PreloadStateExtraType> >(name: "extra", resolve: context =>
     {
         var preloadState = context.Source;
         return(preloadState switch
         {
             ActionExecutionState actionExecutionState => new PreloadStateExtra(nameof(ActionExecutionState),
                                                                                actionExecutionState.ExecutedBlockCount,
                                                                                actionExecutionState.TotalBlockCount),
             BlockDownloadState blockDownloadState => new PreloadStateExtra(nameof(BlockDownloadState),
                                                                            blockDownloadState.ReceivedBlockCount,
                                                                            blockDownloadState.TotalBlockCount),
             BlockHashDownloadState blockHashDownloadState => new PreloadStateExtra(
                 nameof(BlockHashDownloadState),
                 blockHashDownloadState.ReceivedBlockHashCount,
                 blockHashDownloadState.EstimatedTotalBlockHashCount),
             BlockVerificationState blockVerificationState => new PreloadStateExtra(
                 nameof(BlockVerificationState),
                 blockVerificationState.VerifiedBlockCount,
                 blockVerificationState.TotalBlockCount),
             StateDownloadState stateDownloadState => new PreloadStateExtra(
                 nameof(StateDownloadState),
                 stateDownloadState.ReceivedIterationCount,
                 stateDownloadState.TotalIterationCount),
             _ => throw new ExecutionError($"Not supported preload state. {preloadState.GetType()}"),
         });
     });
        public async Task PreloadFromNominer()
        {
            Swarm <DumbAction> minerSwarm    = _swarms[0];
            Swarm <DumbAction> receiverSwarm = _swarms[1];
            var fxForNominers = new StoreFixture[2];

            fxForNominers[0] = new DefaultStoreFixture(memory: true);
            fxForNominers[1] = new DefaultStoreFixture(memory: true);
            var policy = new BlockPolicy <DumbAction>();
            var blockChainsForNominers = new[]
            {
                TestUtils.MakeBlockChain(policy, fxForNominers[0].Store),
                TestUtils.MakeBlockChain(policy, fxForNominers[1].Store),
            };
            var nominerSwarm0 = CreateSwarm(blockChainsForNominers[0]);
            var nominerSwarm1 = CreateSwarm(blockChainsForNominers[1]);

            BlockChain <DumbAction> minerChain    = _blockchains[0];
            BlockChain <DumbAction> receiverChain = _blockchains[1];

            foreach (int i in Enumerable.Range(0, 10))
            {
                await minerChain.MineBlock(_fx1.Address1);
            }

            var actualStates = new List <PreloadState>();
            var progress     = new Progress <PreloadState>(state =>
            {
                lock (actualStates)
                {
                    actualStates.Add(state);
                }
            });

            try
            {
                await StartAsync(minerSwarm);
                await StartAsync(nominerSwarm0);
                await StartAsync(nominerSwarm1);

                minerSwarm.FindNextHashesChunkSize    = 2;
                nominerSwarm0.FindNextHashesChunkSize = 2;
                nominerSwarm1.FindNextHashesChunkSize = 2;

                await nominerSwarm0.AddPeersAsync(new[] { minerSwarm.AsPeer }, null);

                await nominerSwarm0.PreloadAsync();

                await nominerSwarm1.AddPeersAsync(new[] { nominerSwarm0.AsPeer }, null);

                await nominerSwarm1.PreloadAsync();

                await receiverSwarm.AddPeersAsync(new[] { nominerSwarm1.AsPeer }, null);

                await receiverSwarm.PreloadAsync(TimeSpan.FromSeconds(15), progress);

                // Await 1 second to make sure all progresses is reported.
                await Task.Delay(1000);

                Assert.Equal(minerChain.BlockHashes, receiverChain.BlockHashes);

                var expectedStates = new List <PreloadState>();

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var state = new BlockHashDownloadState
                    {
                        EstimatedTotalBlockHashCount = 10,
                        ReceivedBlockHashCount       = i,
                        SourcePeer = nominerSwarm1.AsPeer as BoundPeer,
                    };
                    expectedStates.Add(state);
                }

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var state = new BlockDownloadState
                    {
                        ReceivedBlockHash  = minerChain[i].Hash,
                        TotalBlockCount    = 10,
                        ReceivedBlockCount = i,
                        SourcePeer         = nominerSwarm1.AsPeer as BoundPeer,
                    };
                    expectedStates.Add(state);
                }

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var state = new BlockVerificationState
                    {
                        VerifiedBlockHash  = minerChain[i].Hash,
                        TotalBlockCount    = 10,
                        VerifiedBlockCount = i,
                    };
                    expectedStates.Add(state);
                }

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var state = new ActionExecutionState
                    {
                        ExecutedBlockHash  = minerChain[i].Hash,
                        TotalBlockCount    = 10,
                        ExecutedBlockCount = i,
                    };
                    expectedStates.Add(state);
                }

                // FIXME: this test does not ensures block download in order
                Assert.Equal(
                    expectedStates.ToHashSet(),
                    actualStates.ToHashSet()
                    );
            }
            finally
            {
                await StopAsync(minerSwarm);
                await StopAsync(nominerSwarm0);
                await StopAsync(nominerSwarm1);
                await StopAsync(receiverSwarm);

                nominerSwarm0.Dispose();
                nominerSwarm1.Dispose();

                fxForNominers[0].Dispose();
                fxForNominers[1].Dispose();
            }
        }
        public async Task Preload()
        {
            Swarm <DumbAction> minerSwarm    = _swarms[0];
            Swarm <DumbAction> receiverSwarm = _swarms[1];

            BlockChain <DumbAction> minerChain    = _blockchains[0];
            BlockChain <DumbAction> receiverChain = _blockchains[1];

            var blocks = new List <Block <DumbAction> >();

            foreach (int i in Enumerable.Range(0, 11))
            {
                blocks.Add(TestUtils.MineNext(
                               previousBlock: i == 0 ? minerChain.Genesis : blocks[i - 1],
                               difficulty: 1024));
                if (i != 10)
                {
                    minerChain.Append(blocks[i]);
                }
            }

            var actualStates = new List <PreloadState>();
            var progress     = new Progress <PreloadState>(state =>
            {
                _logger.Information("Received a progress event: {@State}", state);
                lock (actualStates)
                {
                    actualStates.Add(state);

                    if (actualStates.Count == 9)
                    {
                        minerChain.Append(blocks[10]);
                    }
                }
            });

            try
            {
                await StartAsync(minerSwarm);

                await receiverSwarm.AddPeersAsync(new[] { minerSwarm.AsPeer }, null);

                _logger.Verbose("Both chains before synchronization:");
                _logger.CompareBothChains(
                    LogEventLevel.Verbose,
                    "Miner chain",
                    minerChain,
                    "Receiver chain",
                    receiverChain
                    );

                minerSwarm.FindNextHashesChunkSize = 2;
                await receiverSwarm.PreloadAsync(TimeSpan.FromSeconds(15), progress);

                // Await 1 second to make sure all progresses is reported.
                await Task.Delay(1000);

                _logger.Verbose(
                    $"Both chains after synchronization ({nameof(receiverSwarm.PreloadAsync)}):"
                    );
                _logger.CompareBothChains(
                    LogEventLevel.Verbose,
                    "Miner chain",
                    minerChain,
                    "Receiver chain",
                    receiverChain
                    );
                Assert.Equal(minerChain.BlockHashes, receiverChain.BlockHashes);

                var expectedStates = new List <PreloadState>();

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var b     = minerChain[i];
                    var state = new BlockHashDownloadState
                    {
                        EstimatedTotalBlockHashCount = 10,
                        ReceivedBlockHashCount       = 1,
                        SourcePeer = minerSwarm.AsPeer as BoundPeer,
                    };
                    expectedStates.Add(state);
                }

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var b     = minerChain[i];
                    var state = new BlockDownloadState
                    {
                        ReceivedBlockHash  = b.Hash,
                        TotalBlockCount    = i == 9 || i == 10 ? 11 : 10,
                        ReceivedBlockCount = i,
                        SourcePeer         = minerSwarm.AsPeer as BoundPeer,
                    };
                    expectedStates.Add(state);
                }

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var b     = minerChain[i];
                    var state = new BlockVerificationState
                    {
                        VerifiedBlockHash  = b.Hash,
                        TotalBlockCount    = i == 9 || i == 10 ? 11 : 10,
                        VerifiedBlockCount = i,
                    };
                    expectedStates.Add(state);
                }

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var b     = minerChain[i];
                    var state = new ActionExecutionState
                    {
                        ExecutedBlockHash  = b.Hash,
                        TotalBlockCount    = 11,
                        ExecutedBlockCount = i,
                    };
                    expectedStates.Add(state);
                }

                _logger.Debug("Expected preload states: {@expectedStates}", expectedStates);
                _logger.Debug("Actual preload states: {@actualStates}", actualStates);

                Assert.Equal(expectedStates.Count, actualStates.Count);
                foreach (var states in expectedStates.Zip(actualStates, ValueTuple.Create))
                {
                    Assert.Equal(states.Item1, states.Item2);
                }
            }
            finally
            {
                await StopAsync(minerSwarm);
                await StopAsync(receiverSwarm);
            }
        }