public bool TryGetAtHeight(int height, [MaybeNullWhen(false)] out HeaderNode?headerNode)
 {
     using (GlobalLocks.ReadOnMainAsync().GetAwaiter().GetResult())
     {
         return(HeadersTree.TryGetNodeOnBestChain(height, out headerNode));
     }
 }
        public bool TryGetNext(HeaderNode headerNode, [MaybeNullWhen(false)] out HeaderNode nextHeaderNode)
        {
            using (GlobalLocks.ReadOnMainAsync().GetAwaiter().GetResult())
            {
                if (IsInBestChain(headerNode) && HeadersTree.TryGetNodeOnBestChain(headerNode.Height + 1, out nextHeaderNode))
                {
                    return(true);
                }

                nextHeaderNode = null;
                return(false);
            }
        }
Exemple #3
0
        /// <summary>
        /// Processes the headers.
        /// It's invoked because of "headers" or "cmpctblock" message
        /// </summary>
        /// <param name="headers">The headers.</param>
        /// <returns></returns>
        private async Task <bool> ProcessHeadersAsync(BlockHeader[] headers)
        {
            int protocolVersion = PeerContext.NegotiatedProtocolVersion.Version;
            int headersCount    = headers.Length;

            if (headersCount == 0)
            {
                logger.LogDebug("Peer didn't returned any headers, let's assume we reached its tip.");
                return(true);
            }

            using (GlobalLocks.ReadOnMainAsync().GetAwaiter().GetResult())
            {
                if (await HandleAsNotConnectingAnnouncementAsync(headers).ConfigureAwait(false))
                {
                    // fully handled as non connecting announcement
                    return(true);
                }

                // compute hashes in parallel to speed up the operation and check sent headers are sequential.
                Parallel.ForEach(headers, header =>
                {
                    header.Hash = _blockHeaderHashCalculator.ComputeHash(header, protocolVersion);
                });
            }

            // Ensure headers are consecutive.
            for (int i = 1; i < headersCount; i++)
            {
                if (headers[i].PreviousBlockHash != headers[i - 1].Hash)
                {
                    Misbehave(20, "Non continuous headers sequence.");
                    return(false);
                }
            }

            //enqueue headers for validation
            await _headerValidator.RequestValidationAsync(new HeadersToValidate(headers, PeerContext)).ConfigureAwait(false);

            return(true);
        }
        public HeaderNode FindForkInGlobalIndex(BlockLocator locator)
        {
            using (GlobalLocks.ReadOnMainAsync().GetAwaiter().GetResult())
            {
                // Find the latest block common to locator and chain - we expect that
                // locator.vHave is sorted descending by height.
                foreach (UInt256?hash in locator.BlockLocatorHashes)
                {
                    if (TryGetKnownHeaderNode(hash, out HeaderNode? pindex))
                    {
                        if (IsInBestChain(pindex))
                        {
                            return(pindex);
                        }

                        if (pindex.GetAncestor(ChainTip.Height) == ChainTip)
                        {
                            return(ChainTip);
                        }
                    }
                }
            }
            return(HeadersTree.Genesis);
        }
        public BlockHeader GetTipHeader()
        {
            using Microsoft.VisualStudio.Threading.AsyncReaderWriterLock.Releaser readMainLock = GlobalLocks.ReadOnMainAsync().GetAwaiter().GetResult();
            if (!_blockHeaderRepository.TryGet(ChainTip.Hash, out BlockHeader? header))
            {
                ThrowHelper.ThrowBlockHeaderRepositoryException($"Unexpected error, cannot fetch the tip at height {ChainTip.Height}.");
            }

            return(header !);
        }
 public BlockLocator?GetLocator(HeaderNode headerNode)
 {
     using Microsoft.VisualStudio.Threading.AsyncReaderWriterLock.Releaser readMainLock = GlobalLocks.ReadOnMainAsync().GetAwaiter().GetResult();
     return(HeadersTree.GetLocator(headerNode));
 }
 public bool TryGetKnownHeaderNode(UInt256?blockHash, [MaybeNullWhen(false)] out HeaderNode node)
 {
     //using var readLock = new ReadLock(this.theLock);
     using Microsoft.VisualStudio.Threading.AsyncReaderWriterLock.Releaser readMainLock = GlobalLocks.ReadOnMainAsync().GetAwaiter().GetResult();
     return(HeadersTree.TryGetNode(blockHash, false, out node));
 }
 public bool TryGetBestChainHeaderNode(UInt256 blockHash, [MaybeNullWhen(false)] out HeaderNode node)
 {
     using Microsoft.VisualStudio.Threading.AsyncReaderWriterLock.Releaser readMainLock = GlobalLocks.ReadOnMainAsync().GetAwaiter().GetResult();
     return(HeadersTree.TryGetNode(blockHash, true, out node));
 }
Exemple #9
0
        private async Task SyncLoopAsync(CancellationToken cancellationToken)
        {
            using Microsoft.VisualStudio.Threading.AsyncReaderWriterLock.Releaser readLock = GlobalLocks.ReadOnMainAsync().GetAwaiter().GetResult();

            HeaderNode?bestHeaderNode = _chainState.BestHeader;

            if (!_chainState.TryGetBlockHeader(bestHeaderNode, out BlockHeader? bestBlockHeader))
            {
                ThrowHelper.ThrowNotSupportedException("BestHeader should always be available, this should never happen");
            }

            if (!_status.IsSynchronizingHeaders)
            {
                _status.IsSynchronizingHeaders = true;
                _status.HeadersSyncTimeout     =
                    _dateTimeProvider.GetTimeMicros()
                    + HEADERS_DOWNLOAD_TIMEOUT_BASE
                    + HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER * (
                        (_dateTimeProvider.GetAdjustedTimeAsUnixTimestamp() - bestBlockHeader.TimeStamp) / _consensusParameters.PowTargetSpacing
                        );

                /* If possible, start at the block preceding the currently
                 * best known header.  This ensures that we always get a
                 * non-empty list of headers back as long as the peer
                 * is up-to-date.  With a non-empty response, we can initialise
                 * the peer's known best block.  This wouldn't be possible
                 * if we requested starting at pindexBestHeader and
                 * got back an empty response.  */
                HeaderNode?pindexStart = bestHeaderNode.Previous ?? bestHeaderNode;

                logger.LogDebug("Starting syncing headers from height {LocatorHeight} (peer starting height: {StartingHeight})", pindexStart.Height, _status.PeerStartingHeight);

                var newGetHeaderRequest = new GetHeadersMessage
                {
                    Version      = (uint)PeerContext.NegotiatedProtocolVersion.Version,
                    BlockLocator = _chainState.GetLocator(pindexStart),
                    HashStop     = UInt256.Zero
                };

                await SendMessageAsync(newGetHeaderRequest).ConfigureAwait(false);
            }

            CheckSyncStallingLocked(bestBlockHeader);

            ConsiderEviction(_dateTimeProvider.GetTime());
        }