Exemple #1
0
        public void ConstructProvenHeaderPayload_Consecutive_Headers()
        {
            var provenHeaderChain = BuildProvenHeaderChain(10);

            var chain = new ChainIndexer(this.Network, provenHeaderChain);

            var consensusManager = new Mock <IConsensusManager>();

            consensusManager.Setup(c => c.Tip).Returns(provenHeaderChain);

            var behavior = new ProvenHeadersConsensusManagerBehavior(chain, this.initialBlockDownloadState, consensusManager.Object, this.peerBanning, this.extendedLoggerFactory, this.Network, this.chainState, this.checkpoints, this.provenBlockHeaderStore, this.connectionManagerSettings);

            var hashes = new List <uint256>();

            for (int i = 1; i < 5; i++)
            {
                var chainedHeaderToAdd = chain.GetHeader(i);
                hashes.Add(chainedHeaderToAdd.HashBlock);
            }
            hashes.Reverse();

            var blockLocator = new BlockLocator {
                Blocks = hashes
            };

            var peerMock = CreatePeerMock();

            behavior.Attach(peerMock.Object);

            var incomingMessage = new IncomingMessage
            {
                Message = new Message(new PayloadProvider().DiscoverPayloads())
                {
                    Magic   = this.Network.Magic,
                    Payload = new GetProvenHeadersPayload(blockLocator),
                }
            };

            var provenBlockHeadersToVerifyAgainst = new List <ProvenBlockHeader>();

            for (int i = 5; i <= provenHeaderChain.Height; i++)
            {
                provenBlockHeadersToVerifyAgainst.Add((ProvenBlockHeader)provenHeaderChain.GetAncestor(i).Header);
            }

            //Trigger the event handler
            peerMock.Object.MessageReceived.ExecuteCallbacksAsync(peerMock.Object, incomingMessage).GetAwaiter().GetResult();

            // Check that the headers we sent is the correct headers.
            var payload = new ProvenHeadersPayload(provenBlockHeadersToVerifyAgainst.ToArray());

            peerMock.Verify(p => p.SendMessageAsync(It.Is <ProvenHeadersPayload>(pl => VerifyHeaders(pl.Headers, provenBlockHeadersToVerifyAgainst)), default(CancellationToken)));
        }
Exemple #2
0
        /// <inheritdoc />
        /// <returns>The <see cref="HeadersPayload"/> instance to announce to the peer, or <see cref="ProvenHeadersPayload"/> if the peers requires it.</returns>
        protected override Payload BuildHeadersAnnouncePayload(IEnumerable <ChainedHeader> headers)
        {
            // Sanity check. That should never happen.
            if (!headers.All(x => x.ProvenBlockHeader != null))
            {
                throw new BlockStoreException("UnexpectedError: BlockHeader is expected to be a ProvenBlockHeader");
            }

            var provenHeadersPayload = new ProvenHeadersPayload(headers.Select(s => s.ProvenBlockHeader).ToArray());

            return(provenHeadersPayload);
        }
Exemple #3
0
        /// <inheritdoc />
        protected override Payload ConstructHeadersPayload(GetHeadersPayload getHeadersPayload, out ChainedHeader lastHeader)
        {
            // If getHeadersPayload isn't a GetProvenHeadersPayload, return base implementation result
            if (!(getHeadersPayload is GetProvenHeadersPayload))
            {
                var headersPayload = base.ConstructHeadersPayload(getHeadersPayload, out lastHeader) as HeadersPayload;

                if (headersPayload == null)
                {
                    this.logger.LogTrace("(-)[INVALID_LOCATOR]:null");
                    return(null);
                }

                return(headersPayload);
            }

            ChainedHeader fork = this.ChainIndexer.FindFork(getHeadersPayload.BlockLocator);

            lastHeader = null;

            if (fork == null)
            {
                this.logger.LogTrace("(-)[INVALID_LOCATOR]:null");
                return(null);
            }

            var provenHeadersPayload = new ProvenHeadersPayload();

            ChainedHeader header = this.GetLastHeaderToSend(fork, getHeadersPayload.HashStop);

            this.logger.LogDebug("Last header that will be sent in headers payload is '{0}'.", header);

            for (int heightIndex = header.Height; heightIndex > fork.Height; heightIndex--)
            {
                ProvenBlockHeader provenBlockHeader = header.ProvenBlockHeader;

                if (provenBlockHeader == null)
                {
                    provenBlockHeader = this.provenBlockHeaderStore.GetAsync(header.Height).GetAwaiter().GetResult();

                    if (provenBlockHeader == null)
                    {
                        // Proven header is not available yet for this header.
                        // This can happen in case headers were requested by the peer right after we advanced consensus tip
                        // So at this moment proven header is not created or not yet saved to headers store for the block connected.
                        this.logger.LogDebug("No PH available for header '{0}'.", header);
                        this.logger.LogTrace("(-)[NO_PH_AVAILABLE]");
                        break;
                    }
                    else if (provenBlockHeader.PosBlockHeader.GetHash() != header.HashBlock)
                    {
                        // Proven header is in the store, but with a wrong hash.
                        // This can happen in case of reorgs, when the store has not yet been updated.
                        // Without this check, we may send headers that aren't consecutive because are built from different branches, and the other peer may ban us.
                        this.logger.LogDebug("Stored PH hash is wrong. Expected: {0}, Found: {1}", header.Header.GetHash(), provenBlockHeader.PosBlockHeader.GetHash());
                        this.logger.LogTrace("(-)[WRONG STORED PH]");
                        break;
                    }
                }

                lastHeader = header;

                provenHeadersPayload.Headers.Add(provenBlockHeader);

                header = header.Previous;
            }

            provenHeadersPayload.Headers.Reverse();

            return(provenHeadersPayload);
        }
Exemple #4
0
        /// <inheritdoc />
        protected override Payload ConstructHeadersPayload(GetHeadersPayload getHeadersPayload, out ChainedHeader lastHeader)
        {
            // If getHeadersPayload isn't a GetProvenHeadersPayload, return base implementation result
            if (!(getHeadersPayload is GetProvenHeadersPayload))
            {
                var headersPayload = base.ConstructHeadersPayload(getHeadersPayload, out lastHeader) as HeadersPayload;

                for (int i = 0; i < headersPayload.Headers.Count; i++)
                {
                    if (headersPayload.Headers[i] is ProvenBlockHeader phHeader)
                    {
                        BlockHeader newHeader = this.chain.Network.Consensus.ConsensusFactory.CreateBlockHeader();
                        newHeader.Bits           = phHeader.Bits;
                        newHeader.Time           = phHeader.Time;
                        newHeader.Nonce          = phHeader.Nonce;
                        newHeader.Version        = phHeader.Version;
                        newHeader.HashMerkleRoot = phHeader.HashMerkleRoot;
                        newHeader.HashPrevBlock  = phHeader.HashPrevBlock;

                        headersPayload.Headers[i] = newHeader;
                    }
                }

                return(headersPayload);
            }

            ChainedHeader fork = this.chain.FindFork(getHeadersPayload.BlockLocator);

            lastHeader = null;

            if (fork == null)
            {
                this.logger.LogTrace("(-)[INVALID_LOCATOR]:null");
                return(null);
            }

            var provenHeadersPayload = new ProvenHeadersPayload();

            ChainedHeader header = this.GetLastHeaderToSend(fork, getHeadersPayload.HashStop);

            for (int heightIndex = header.Height; heightIndex > fork.Height; heightIndex--)
            {
                if (!(header.Header is ProvenBlockHeader provenBlockHeader))
                {
                    this.logger.LogTrace("Invalid proven header, try loading it from the store.");

                    provenBlockHeader = this.provenBlockHeaderStore.GetAsync(header.Height).GetAwaiter().GetResult();

                    if (provenBlockHeader == null)
                    {
                        // Proven header is not available yet for this header.
                        // This can happen in case headers were requested by the peer right after we advanced consensus tip
                        // So at this moment proven header is not created or not yet saved to headers store for the block connected.
                        this.logger.LogDebug("No PH available for header '{0}'.", header);
                        this.logger.LogTrace("(-)[NO_PH_AVAILABLE]");
                        break;
                    }
                }

                lastHeader = header;

                provenHeadersPayload.Headers.Add(provenBlockHeader);

                header = header.Previous;
            }

            provenHeadersPayload.Headers.Reverse();

            return(provenHeadersPayload);
        }