public HeaderNode AddToBlockIndex(BlockHeader header) { using (GlobalLocks.WriteOnMainAsync().GetAwaiter().GetResult()) { // Check for duplicate if (TryGetKnownHeaderNode(header.Hash, out HeaderNode? headerNode)) { return(headerNode); } if (!TryGetKnownHeaderNode(header.PreviousBlockHash, out HeaderNode? previousHeader)) { ThrowHelper.ThrowNotSupportedException("Previous hash not found (shouldn't happen)."); } headerNode = new HeaderNode(header, previousHeader); if (BestHeader == null || BestHeader.ChainWork < headerNode.ChainWork) { BestHeader = headerNode; } HeadersTree.Add(headerNode); _blockHeaderRepository.TryAdd(header); return(headerNode); } }
/// <summary> /// Finds the ancestor of this entry in the chain that matches the given block height. /// </summary> /// <param name="height">The block height to search for.</param> /// <returns>The ancestor of this chain at the specified height.</returns> public HeaderNode?GetAncestor(int height) { if (height > Height || height < 0) { return(null); } HeaderNode current = this; int heightWalk = Height; while (heightWalk > height) { int heightSkip = GetSkipHeight(heightWalk); int heightSkipPrev = GetSkipHeight(heightWalk - 1); //walk.Previous.Skip.Height; if (current.Skip != null && (heightSkip == height || (heightSkip > height && !(heightSkipPrev < (heightSkip - 2) && heightSkipPrev >= height)))) { // Only follow Skip if pprev->pskip isn't better than pskip->pprev. current = current.Skip; heightWalk = heightSkip; } else { current = current.Previous !; heightWalk--; } } return(current); }
public HeadersTree(ILogger <HeadersTree> logger, IConsensusParameters consensusParameters) { _logger = logger; _consensusParameters = consensusParameters ?? throw new ArgumentNullException(nameof(consensusParameters)); Genesis = HeaderNode.GenerateGenesis(_consensusParameters.GenesisHeader); ResetToGenesis(); }
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); } }
/// <summary> /// Tries to get the <see cref="HeaderNode" /> giving its hash. /// </summary> /// <param name="blockHash">The block hash.</param> /// <param name="onlyBestChain">if set to <c>true</c> check only headers that belong to the best chain.</param> /// <param name="node">The header node having the passed <paramref name="blockHash"/>.</param> /// <returns> /// <c>true</c> if the result has been found, <see langword="false" /> otherwise. /// </returns> public bool TryGetNode(UInt256?blockHash, bool onlyBestChain, [MaybeNullWhen(false)] out HeaderNode node) { if (blockHash == null) { node = null; return(false); } using (new ReadLock(_theLock)) { return(onlyBestChain ? TryGetNodeOnBestChainNoLock(blockHash, out node !) : _knownHeaders.TryGetValue(blockHash, out node !)); } }
/// <summary> /// Tries to get the <see cref="HeaderNode" /> on best chain at a specified height. /// </summary> /// <param name="height">The height.</param> /// <param name="node">The header node at the specified height.</param> /// <returns> /// <c>true</c> if the result has been found, <see langword="false" /> otherwise. /// </returns> public bool TryGetNodeOnBestChain(int height, [MaybeNullWhen(false)] out HeaderNode node) { using (new ReadLock(_theLock)) { if (height > _height) { node = null !; return(false); } node = GetHeaderNodeNoLock(height); return(true); } }
public ChainState(ILogger <ChainState> logger, IHeadersTree headersTree, ICoinsView coinsView, IBlockHeaderRepository blockHeaderRepository, IConsensusParameters consensusParameters) { this.logger = logger; HeadersTree = headersTree; this.coinsView = coinsView; _blockHeaderRepository = blockHeaderRepository; _consensusParameters = consensusParameters; ChainTip = headersTree.Genesis; BestHeader = headersTree.Genesis; _blockHeaderRepository.TryAdd(consensusParameters.GenesisHeader); }
internal HeaderNode LastCommonAncestor(HeaderNode otherHeaderNode) { //move both chains at the height of the lower one HeaderNode?left = Height > otherHeaderNode.Height ? GetAncestor(otherHeaderNode.Height) : this; HeaderNode?right = otherHeaderNode.Height > Height?otherHeaderNode.GetAncestor(Height) : otherHeaderNode; // walk back walking previous header, until we find that both are the header while (left != right && left != null && right != null) { left = left.Previous; right = right.Previous; } //at this point returning left or right is the same, both are equals and at worst case they go back down to genesis return(left !); }
internal HeaderNode(BlockHeader header, HeaderNode previous) { if (header == null) { ThrowHelper.ThrowArgumentNullException(nameof(header)); } if (header.Hash == null) { ThrowHelper.ThrowArgumentException($"{nameof(header)} hash cannot be null."); } Hash = header.Hash; Height = previous.Height + 1; Previous = previous; ChainWork = previous.ChainWork + new Target(header.Bits).GetBlockProof(); Skip = previous.GetAncestor(GetSkipHeight(Height)); _status = (int)HeaderValidityStatuses.ValidTree; //pindexNew.TimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev.TimeMax, pindexNew.Time) : pindexNew.Time); }
public bool TryGetBlockHeader(HeaderNode headerNode, [MaybeNullWhen(false)] out BlockHeader blockHeader) { return(_blockHeaderRepository.TryGet(headerNode.Hash, out blockHeader)); }
public bool IsInBestChain(HeaderNode headerNode) { return(HeadersTree.IsInBestChain(headerNode)); }
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)); }
/// <summary> /// Determines whether <paramref name="expectedAncestor"/> is in same chain (can be this header itself). /// </summary> /// <param name="expectedAncestor">The expected ancestor.</param> /// <returns> /// <c>true</c> if [is in same chain] [the specified expected ancestor]; otherwise, <c>false</c>. /// </returns> public bool IsInSameChain(HeaderNode expectedAncestor) { return(this == expectedAncestor || GetAncestor(expectedAncestor.Height)?.Hash == expectedAncestor.Hash); }