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))); }
/// <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); }
/// <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); }
/// <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); }