void Intercept(IncomingMessage message, Action act) { var inv = message.Message.Payload as InvPayload; if (inv != null) { if (inv.Inventory.Any(i => ((i.Type & InventoryType.MSG_BLOCK) != 0) && !Chain.Contains(i.Hash))) { _Refresh.Dispose(); //No need of periodical refresh, the peer is notifying us if (AutoSync) { TrySync(); } } } // == GetHeadersPayload == // represents our height from the peer's point of view // it is sent from the peer on first connect, in response to Inv(Block) // or in response to HeaderPayload until an empty array is returned // this payload notifies peers of our current best validated height // use the ChainState.HighestValidatedPoW property (not Chain.Tip) // if the peer is behind/equal to our best height an empty array is sent back // Ignoring getheaders from peers because node is in initial block download var getheaders = message.Message.Payload as GetHeadersPayload; if (getheaders != null && CanRespondToGetHeaders && (!this.SharedState.IsInitialBlockDownload || this.AttachedNode.Behavior <ConnectionManagerBehavior>().Whitelisted)) // if not in IBD whitelisted won't be checked { HeadersPayload headers = new HeadersPayload(); var highestPow = SharedState.HighestValidatedPoW; highestPow = Chain.GetBlock(highestPow.HashBlock); var fork = Chain.FindFork(getheaders.BlockLocators); if (fork != null) { if (highestPow == null || fork.Height > highestPow.Height) { fork = null; //fork not yet validated } if (fork != null) { foreach (var header in Chain.EnumerateToTip(fork).Skip(1)) { if (header.Height > highestPow.Height) { break; } headers.Headers.Add(header.Header); if (header.HashBlock == getheaders.HashStop || headers.Headers.Count == 2000) { break; } } } } AttachedNode.SendMessageAsync(headers); } // == HeadersPayload == // represents the peers height from our point view // this updates the pending tip parameter which is the // peers current best validated height // if the peer's height is higher Chain.Tip is updated to have // the most PoW header // is sent in response to GetHeadersPayload or is solicited by the // peer when a new block is validated (and not in IBD) var newheaders = message.Message.Payload as HeadersPayload; var pendingTipBefore = GetPendingTipOrChainTip(); if (newheaders != null && CanSync) { // TODO: implement MAX_HEADERS_RESULTS in NBitcoin.HeadersPayload var tip = GetPendingTipOrChainTip(); foreach (var header in newheaders.Headers) { var prev = tip.FindAncestorOrSelf(header.HashPrevBlock); if (prev == null) { break; } tip = new ChainedBlock(header, header.GetHash(), prev); var validated = Chain.GetBlock(tip.HashBlock) != null || tip.Validate(AttachedNode.Network); validated &= !SharedState.IsMarkedInvalid(tip.HashBlock); if (!validated) { invalidHeaderReceived = true; break; } _PendingTip = tip; } if (_PendingTip.ChainWork > Chain.Tip.ChainWork) { Chain.SetTip(_PendingTip); } var chainedPendingTip = Chain.GetBlock(_PendingTip.HashBlock); if (chainedPendingTip != null) { _PendingTip = chainedPendingTip; //This allows garbage collection to collect the duplicated pendingtip and ancestors } if (newheaders.Headers.Count != 0 && pendingTipBefore.HashBlock != GetPendingTipOrChainTip().HashBlock) { TrySync(); } Interlocked.Decrement(ref _SynchingCount); } act(); }
void Intercept(IncomingMessage message, Action act) { var inv = message.Message.Payload as InvPayload; if (inv != null) { if (inv.Inventory.Any(i => ((i.Type & InventoryType.MSG_BLOCK) != 0) && !Chain.Contains(i.Hash))) { _Refresh.Dispose(); //No need of periodical refresh, the peer is notifying us if (AutoSync) { TrySync(); } } } var getheaders = message.Message.Payload as GetHeadersPayload; if (getheaders != null && CanRespondToGetHeaders && !StripHeader) { HeadersPayload headers = new HeadersPayload(); var highestPow = SharedState.HighestValidatedPoW; highestPow = highestPow == null ? null : Chain.GetBlock(highestPow.HashBlock); var fork = Chain.FindFork(getheaders.BlockLocators); if (fork != null) { if (highestPow != null && fork.Height > highestPow.Height) { fork = null; //fork not yet validated } if (fork != null) { foreach (var header in Chain.EnumerateToTip(fork).Skip(1)) { if (highestPow != null && header.Height > highestPow.Height) { break; } headers.Headers.Add(header.Header); if (header.HashBlock == getheaders.HashStop || headers.Headers.Count == 2000) { break; } } } } AttachedNode.SendMessageAsync(headers); } var newheaders = message.Message.Payload as HeadersPayload; var pendingTipBefore = GetPendingTipOrChainTip(); if (newheaders != null && CanSync) { var tip = GetPendingTipOrChainTip(); foreach (var header in newheaders.Headers) { var prev = tip.FindAncestorOrSelf(header.HashPrevBlock); if (prev == null) { break; } tip = new ChainedBlock(header, header.GetHash(), prev); var validated = Chain.GetBlock(tip.HashBlock) != null || (SkipPoWCheck || tip.Validate(AttachedNode.Network)); validated &= !SharedState.IsMarkedInvalid(tip.HashBlock); if (!validated) { invalidHeaderReceived = true; break; } _PendingTip = tip; } bool isHigherBlock = false; if (SkipPoWCheck) { isHigherBlock = _PendingTip.Height > Chain.Tip.Height; } else { isHigherBlock = _PendingTip.GetChainWork(true) > Chain.Tip.GetChainWork(true); } if (isHigherBlock) { Chain.SetTip(_PendingTip); if (StripHeader) { _PendingTip.StripHeader(); } } var chainedPendingTip = Chain.GetBlock(_PendingTip.HashBlock); if (chainedPendingTip != null) { _PendingTip = chainedPendingTip; //This allows garbage collection to collect the duplicated pendingtip and ancestors } if (newheaders.Headers.Count != 0 && pendingTipBefore.HashBlock != GetPendingTipOrChainTip().HashBlock) { TrySync(); } Interlocked.Decrement(ref _SynchingCount); } act(); }