コード例 #1
0
ファイル: Downloader.cs プロジェクト: ocag91370/PluralVideos
 public Downloader(DownloaderOptions options)
 {
     this.options = options;
     api          = new PluralSightApi(options.Timeout);
     queue        = new TaskQueue();
     queue.ProcessCompleteEvent += ClipDownloaded;
 }
コード例 #2
0
        public FullSyncFeed(ISyncModeSelector syncModeSelector, ILogManager logManager)
            : base(logManager)
        {
            _syncModeSelector = syncModeSelector ?? throw new ArgumentNullException(nameof(syncModeSelector));

            DownloaderOptions options = BuildOptions();

            _blocksRequest = new BlocksRequest(options);

            _syncModeSelector.Changed += SyncModeSelectorOnChanged;
        }
コード例 #3
0
 private static async Task RunDownloadOptions(DownloaderOptions options)
 {
     try
     {
         var downloader = new Downloader(options);
         await downloader.RunAsync();
     }
     catch (Exception exception)
     {
         Utils.WriteRedText($"Error occured: {exception.Message}");
     }
 }
コード例 #4
0
ファイル: Downloader.cs プロジェクト: plamenti/PluralVideos
        public Downloader(DownloaderOptions options)
        {
            if (options.Threads > 10)
            {
                throw new InvalidOperationException();
            }

            this.options = options;
            api          = new PluralSightApi(options.Timeout);
            queue        = new TaskQueue(options.Threads);
            queue.ProcessCompleteEvent += ClipDownloaded;
        }
コード例 #5
0
    public async Task Can_reach_terminal_block(long headNumber, int options, int threshold, bool withBeaconPivot)
    {
        UInt256 ttd = 10000000;

        BlockTreeTests.BlockTreeTestScenario.ScenarioBuilder blockTrees = BlockTreeTests.BlockTreeTestScenario
                                                                          .GoesLikeThis()
                                                                          .WithBlockTrees(4, (int)headNumber + 1, true, ttd)
                                                                          .InsertBeaconPivot(16)
                                                                          .InsertHeaders(4, 15)
                                                                          .InsertBeaconBlocks(17, headNumber, BlockTreeTests.BlockTreeTestScenario.ScenarioBuilder.TotalDifficultyMode.Null);
        BlockTree              notSyncedTree     = blockTrees.NotSyncedTree;
        BlockTree              syncedTree        = blockTrees.SyncedTree;
        Context                ctx               = new(notSyncedTree);
        DownloaderOptions      downloaderOptions = (DownloaderOptions)options;
        InMemoryReceiptStorage receiptStorage    = new();
        MemDb       metadataDb  = blockTrees.NotSyncedTreeBuilder.MetadataDb;
        PoSSwitcher posSwitcher = new(new MergeConfig()
        {
            Enabled = true, TerminalTotalDifficulty = $"{ttd}"
        }, new SyncConfig(), metadataDb, notSyncedTree,
                                      RopstenSpecProvider.Instance, LimboLogs.Instance);
        BeaconPivot beaconPivot = new(new SyncConfig(), metadataDb, notSyncedTree, LimboLogs.Instance);

        if (withBeaconPivot)
        {
            beaconPivot.EnsurePivot(blockTrees.SyncedTree.FindHeader(16, BlockTreeLookupOptions.None));
        }

        MergeBlockDownloader downloader = new(
            posSwitcher,
            beaconPivot,
            ctx.Feed,
            ctx.PeerPool,
            notSyncedTree,
            Always.Valid,
            Always.Valid,
            NullSyncReport.Instance,
            receiptStorage,
            RopstenSpecProvider.Instance,
            CreateMergePeerChoiceStrategy(posSwitcher, beaconPivot),
            new ChainLevelHelper(notSyncedTree, beaconPivot, new SyncConfig(), LimboLogs.Instance),
            Substitute.For <ISyncProgressResolver>(),
            LimboLogs.Instance);

        SyncPeerMock syncPeer = new(syncedTree, false, Response.AllCorrect, 16000000);
        PeerInfo     peerInfo = new(syncPeer);
        await downloader.DownloadBlocks(peerInfo, new BlocksRequest(downloaderOptions), CancellationToken.None);

        Assert.True(posSwitcher.HasEverReachedTerminalBlock());
    }
コード例 #6
0
        private DownloaderOptions BuildOptions()
        {
            DownloaderOptions options = DownloaderOptions.MoveToMain;

            if (_syncConfig.DownloadReceiptsInFastSync)
            {
                options |= DownloaderOptions.WithReceipts;
            }

            if (_syncConfig.DownloadBodiesInFastSync)
            {
                options |= DownloaderOptions.WithBodies;
            }

            return(options);
        }
コード例 #7
0
 public Downloader(DownloaderOptions options)
 {
     this.options       = options;
     pluralsightService = new PluralsightService();
     downloadClient     = new DownloadClient(options.Timeout);
 }
コード例 #8
0
        public override async Task <long> DownloadBlocks(PeerInfo?bestPeer, BlocksRequest blocksRequest,
                                                         CancellationToken cancellation)
        {
            if (_beaconPivot.BeaconPivotExists() == false && _poSSwitcher.HasEverReachedTerminalBlock() == false)
            {
                return(await base.DownloadBlocks(bestPeer, blocksRequest, cancellation));
            }

            if (bestPeer == null)
            {
                string message = $"Not expecting best peer to be null inside the {nameof(BlockDownloader)}";
                if (_logger.IsError)
                {
                    _logger.Error(message);
                }
                throw new ArgumentNullException(message);
            }

            DownloaderOptions options = blocksRequest.Options;
            bool downloadReceipts     = (options & DownloaderOptions.WithReceipts) == DownloaderOptions.WithReceipts;
            bool shouldProcess        = (options & DownloaderOptions.Process) == DownloaderOptions.Process;
            bool shouldMoveToMain     = (options & DownloaderOptions.MoveToMain) == DownloaderOptions.MoveToMain;

            int  blocksSynced  = 0;
            long currentNumber = _blockTree.BestKnownNumber;

            if (_logger.IsTrace)
            {
                _logger.Trace(
                    $"MergeBlockDownloader GetCurrentNumber: currentNumber {currentNumber}, beaconPivotExists: {_beaconPivot.BeaconPivotExists()}, BestSuggestedBody: {_blockTree.BestSuggestedBody?.Number}, BestKnownNumber: {_blockTree.BestKnownNumber}, BestPeer: {bestPeer}, BestKnownBeaconNumber {_blockTree.BestKnownBeaconNumber}");
            }

            bool HasMoreToSync(out BlockHeader[]?headers, out int headersToRequest)
            {
                if (_logger.IsDebug)
                {
                    _logger.Debug($"Continue full sync with {bestPeer} (our best {_blockTree.BestKnownNumber})");
                }

                headersToRequest = Math.Min(_syncBatchSize.Current, bestPeer.MaxHeadersPerRequest());
                if (_logger.IsTrace)
                {
                    _logger.Trace(
                        $"Full sync request {currentNumber}+{headersToRequest} to peer {bestPeer} with {bestPeer.HeadNumber} blocks. Got {currentNumber} and asking for {headersToRequest} more.");
                }

                // Note: blocksRequest.NumberOfLatestBlocksToBeIgnored not accounted for
                headers = _chainLevelHelper.GetNextHeaders(headersToRequest, bestPeer.HeadNumber);
                if (headers == null || headers.Length <= 1)
                {
                    if (_logger.IsTrace)
                    {
                        _logger.Trace("Chain level helper got no headers suggestion");
                    }
                    return(false);
                }

                return(true);
            }

            while (HasMoreToSync(out BlockHeader[]? headers, out int headersToRequest))
            {
                if (cancellation.IsCancellationRequested)
                {
                    return(blocksSynced);                                      // check before every heavy operation
                }
                Block[]? blocks          = null;
                TxReceipt[]?[]? receipts = null;
                if (_logger.IsTrace)
                {
                    _logger.Trace(
                        $"Downloading blocks from peer. CurrentNumber: {currentNumber}, BeaconPivot: {_beaconPivot.PivotNumber}, BestPeer: {bestPeer}, HeaderToRequest: {headersToRequest}");
                }

                BlockDownloadContext context = new(_specProvider, bestPeer, headers !, downloadReceipts, _receiptsRecovery);

                if (cancellation.IsCancellationRequested)
                {
                    return(blocksSynced);                                      // check before every heavy operation
                }
                await RequestBodies(bestPeer, cancellation, context);

                if (downloadReceipts)
                {
                    if (cancellation.IsCancellationRequested)
                    {
                        return(blocksSynced); // check before every heavy operation
                    }
                    await RequestReceipts(bestPeer, cancellation, context);
                }

                _sinceLastTimeout++;
                if (_sinceLastTimeout > 2)
                {
                    _syncBatchSize.Expand();
                }

                blocks   = context.Blocks;
                receipts = context.ReceiptsForBlocks;

                if (!(blocks?.Length > 0))
                {
                    if (_logger.IsTrace)
                    {
                        _logger.Trace("Break early due to no blocks.");
                    }
                    break;
                }

                for (int blockIndex = 0; blockIndex < blocks.Length; blockIndex++)
                {
                    if (cancellation.IsCancellationRequested)
                    {
                        if (_logger.IsTrace)
                        {
                            _logger.Trace("Peer sync cancelled");
                        }
                        break;
                    }

                    Block currentBlock = blocks[blockIndex];
                    if (_logger.IsTrace)
                    {
                        _logger.Trace($"Received {currentBlock} from {bestPeer}");
                    }

                    if (currentBlock.IsBodyMissing)
                    {
                        throw new EthSyncException($"{bestPeer} didn't send body for block {currentBlock.ToString(Block.Format.Short)}.");
                    }

                    // can move this to block tree now?
                    if (!_blockValidator.ValidateSuggestedBlock(currentBlock))
                    {
                        throw new EthSyncException($"{bestPeer} sent an invalid block {currentBlock.ToString(Block.Format.Short)}.");
                    }

                    if (shouldProcess)
                    {
                        // covering edge case during fastSyncTransition when we're trying to SuggestBlock without the state
                        bool headIsGenesis = _blockTree.Head?.IsGenesis ?? false;
                        bool toBeProcessedIsNotBlockOne = currentBlock.Number > 1;
                        bool isFastSyncTransition       = headIsGenesis && toBeProcessedIsNotBlockOne;
                        if (isFastSyncTransition)
                        {
                            long bestFullState = _syncProgressResolver.FindBestFullState();
                            shouldProcess = currentBlock.Number > bestFullState && bestFullState != 0;
                            if (!shouldProcess)
                            {
                                if (_logger.IsInfo)
                                {
                                    _logger.Info($"Skipping processing during fastSyncTransition, currentBlock: {currentBlock}, bestFullState: {bestFullState}");
                                }
                                downloadReceipts = true;
                            }
                        }
                    }

                    if (downloadReceipts)
                    {
                        TxReceipt[]? contextReceiptsForBlock = receipts ![blockIndex];
                        if (currentBlock.Header.HasBody && contextReceiptsForBlock == null)
                        {
                            throw new EthSyncException($"{bestPeer} didn't send receipts for block {currentBlock.ToString(Block.Format.Short)}.");
                        }
                    }
コード例 #9
0
        public async Task <long> DownloadBlocks(PeerInfo bestPeer, BlocksRequest blocksRequest, CancellationToken cancellation)
        {
            if (bestPeer == null)
            {
                string message = $"Not expecting best peer to be null inside the {nameof(BlockDownloader)}";
                if (_logger.IsError)
                {
                    _logger.Error(message);
                }
                throw new ArgumentNullException(message);
            }

            var receiptsRecovery = new ReceiptsRecovery(new EthereumEcdsa(_specProvider.ChainId, _logManager), _specProvider);

            DownloaderOptions options = blocksRequest.Options;
            bool downloadReceipts     = (options & DownloaderOptions.WithReceipts) == DownloaderOptions.WithReceipts;
            bool shouldProcess        = (options & DownloaderOptions.Process) == DownloaderOptions.Process;
            bool shouldMoveToMain     = (options & DownloaderOptions.MoveToMain) == DownloaderOptions.MoveToMain;

            int blocksSynced        = 0;
            int ancestorLookupLevel = 0;

            long currentNumber = Math.Max(0, Math.Min(_blockTree.BestKnownNumber, bestPeer.HeadNumber - 1));

            // pivot number - 6 for uncle validation
            // long currentNumber = Math.Max(Math.Max(0, pivotNumber - 6), Math.Min(_blockTree.BestKnownNumber, bestPeer.HeadNumber - 1));

            while (bestPeer.TotalDifficulty > (_blockTree.BestSuggestedHeader?.TotalDifficulty ?? 0) && currentNumber <= bestPeer.HeadNumber)
            {
                if (_logger.IsDebug)
                {
                    _logger.Debug($"Continue full sync with {bestPeer} (our best {_blockTree.BestKnownNumber})");
                }

                long blocksLeft       = bestPeer.HeadNumber - currentNumber - (blocksRequest.NumberOfLatestBlocksToBeIgnored ?? 0);
                int  headersToRequest = (int)Math.Min(blocksLeft + 1, _syncBatchSize.Current);
                if (headersToRequest <= 1)
                {
                    break;
                }

                headersToRequest = Math.Min(headersToRequest, bestPeer.MaxHeadersPerRequest());
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Full sync request {currentNumber}+{headersToRequest} to peer {bestPeer} with {bestPeer.HeadNumber} blocks. Got {currentNumber} and asking for {headersToRequest} more.");
                }

                if (cancellation.IsCancellationRequested)
                {
                    return(blocksSynced);                                      // check before every heavy operation
                }
                BlockHeader[] headers = await RequestHeaders(bestPeer, cancellation, currentNumber, headersToRequest);

                BlockDownloadContext context = new(_specProvider, bestPeer, headers, downloadReceipts, receiptsRecovery);

                if (cancellation.IsCancellationRequested)
                {
                    return(blocksSynced);                                      // check before every heavy operation
                }
                await RequestBodies(bestPeer, cancellation, context);

                if (downloadReceipts)
                {
                    if (cancellation.IsCancellationRequested)
                    {
                        return(blocksSynced);                                      // check before every heavy operation
                    }
                    await RequestReceipts(bestPeer, cancellation, context);
                }

                _sinceLastTimeout++;
                if (_sinceLastTimeout > 2)
                {
                    _syncBatchSize.Expand();
                }

                Block[] blocks    = context.Blocks;
                Block   blockZero = blocks[0];
                if (context.FullBlocksCount > 0)
                {
                    bool parentIsKnown = _blockTree.IsKnownBlock(blockZero.Number - 1, blockZero.ParentHash);
                    if (!parentIsKnown)
                    {
                        ancestorLookupLevel++;
                        if (ancestorLookupLevel >= _ancestorJumps.Length)
                        {
                            if (_logger.IsWarn)
                            {
                                _logger.Warn($"Could not find common ancestor with {bestPeer}");
                            }
                            throw new EthSyncException("Peer with inconsistent chain in sync");
                        }

                        int ancestorJump = _ancestorJumps[ancestorLookupLevel] - _ancestorJumps[ancestorLookupLevel - 1];
                        currentNumber = currentNumber >= ancestorJump ? (currentNumber - ancestorJump) : 0L;
                        continue;
                    }
                }

                ancestorLookupLevel = 0;
                for (int blockIndex = 0; blockIndex < context.FullBlocksCount; blockIndex++)
                {
                    if (cancellation.IsCancellationRequested)
                    {
                        if (_logger.IsTrace)
                        {
                            _logger.Trace("Peer sync cancelled");
                        }
                        break;
                    }

                    Block currentBlock = blocks[blockIndex];
                    if (_logger.IsTrace)
                    {
                        _logger.Trace($"Received {currentBlock} from {bestPeer}");
                    }

                    // can move this to block tree now?
                    if (!_blockValidator.ValidateSuggestedBlock(currentBlock))
                    {
                        throw new EthSyncException($"{bestPeer} sent an invalid block {currentBlock.ToString(Block.Format.Short)}.");
                    }

                    if (downloadReceipts)
                    {
                        TxReceipt[]? contextReceiptsForBlock = context.ReceiptsForBlocks ![blockIndex];
コード例 #10
0
 public BlocksRequest(DownloaderOptions options)
 {
     Options = options;
 }
コード例 #11
0
 public BlocksRequest(DownloaderOptions options, int?numberOfLatestBlocksToBeIgnored)
 {
     Options = options;
     NumberOfLatestBlocksToBeIgnored = numberOfLatestBlocksToBeIgnored;
 }
コード例 #12
0
    public async Task Merge_Happy_path(long pivot, long headNumber, int options, int threshold, long insertedBeaconBlocks)
    {
        BlockTreeTests.BlockTreeTestScenario.ScenarioBuilder blockTrees = BlockTreeTests.BlockTreeTestScenario
                                                                          .GoesLikeThis()
                                                                          .WithBlockTrees(4, (int)headNumber + 1)
                                                                          .InsertBeaconPivot(pivot)
                                                                          .InsertHeaders(4, pivot - 1)
                                                                          .InsertBeaconBlocks(pivot + 1, insertedBeaconBlocks, BlockTreeTests.BlockTreeTestScenario.ScenarioBuilder.TotalDifficultyMode.Null);
        BlockTree         notSyncedTree     = blockTrees.NotSyncedTree;
        BlockTree         syncedTree        = blockTrees.SyncedTree;
        Context           ctx               = new(notSyncedTree);
        DownloaderOptions downloaderOptions = (DownloaderOptions)options;
        bool withReceipts = downloaderOptions == DownloaderOptions.WithReceipts;
        InMemoryReceiptStorage receiptStorage = new();
        MemDb       metadataDb  = blockTrees.NotSyncedTreeBuilder.MetadataDb;
        PoSSwitcher posSwitcher = new(new MergeConfig()
        {
            Enabled = true, TerminalTotalDifficulty = "0"
        }, new SyncConfig(), metadataDb, notSyncedTree,
                                      RopstenSpecProvider.Instance, LimboLogs.Instance);
        BeaconPivot beaconPivot = new(new SyncConfig(), metadataDb, notSyncedTree, LimboLogs.Instance);

        beaconPivot.EnsurePivot(blockTrees.SyncedTree.FindHeader(pivot, BlockTreeLookupOptions.None));
        beaconPivot.ProcessDestination = blockTrees.SyncedTree.FindHeader(pivot, BlockTreeLookupOptions.None);

        MergeBlockDownloader downloader = new(
            posSwitcher,
            beaconPivot,
            ctx.Feed,
            ctx.PeerPool,
            notSyncedTree,
            Always.Valid,
            Always.Valid,
            NullSyncReport.Instance,
            receiptStorage,
            RopstenSpecProvider.Instance,
            CreateMergePeerChoiceStrategy(posSwitcher, beaconPivot),
            new ChainLevelHelper(notSyncedTree, beaconPivot, new SyncConfig(), LimboLogs.Instance),
            Substitute.For <ISyncProgressResolver>(),
            LimboLogs.Instance);

        Response responseOptions = Response.AllCorrect;

        if (withReceipts)
        {
            responseOptions |= Response.WithTransactions;
        }

        SyncPeerMock syncPeer = new(syncedTree, withReceipts, responseOptions, 16000000);
        PeerInfo     peerInfo = new(syncPeer);
        await downloader.DownloadBlocks(peerInfo, new BlocksRequest(downloaderOptions), CancellationToken.None);

        ctx.BlockTree.BestSuggestedHeader.Number.Should().Be(Math.Max(0, insertedBeaconBlocks));
        ctx.BlockTree.BestKnownNumber.Should().Be(Math.Max(0, insertedBeaconBlocks));

        int receiptCount = 0;

        for (int i = (int)Math.Max(0, headNumber - threshold); i < peerInfo.HeadNumber; i++)
        {
            if (i % 3 == 0)
            {
                receiptCount += 2;
            }
        }

        receiptStorage.Count.Should().Be(withReceipts ? receiptCount : 0);
        beaconPivot.ProcessDestination?.Number.Should().Be(insertedBeaconBlocks);
    }