void AttachedNode_MessageReceived(Node node, IncomingMessage message) { var filterload = message.Message.Payload as FilterLoadPayload; if (filterload != null) { _Filter = filterload.Object; } var getdata = message.Message.Payload as GetDataPayload; if (getdata != null) { foreach (var inv in getdata.Inventory) { if (inv.Type == InventoryType.MSG_FILTERED_BLOCK && _Filter != null) { var merkle = new MerkleBlock(_Blocks[inv.Hash], _Filter); AttachedNode.SendMessageAsync(new MerkleBlockPayload(merkle)); foreach (var tx in merkle.PartialMerkleTree.GetMatchedTransactions()) { if (_Known.TryAdd(tx, tx)) { AttachedNode.SendMessageAsync(new InvPayload(InventoryType.MSG_TX, tx)); } } } if (inv.Type == InventoryType.MSG_TX) { AttachedNode.SendMessageAsync(new TxPayload(_Transactions[inv.Hash])); } } } }
internal void StartDownload(uint256 block) { if (_Puller._Map.TryAdd(block, this)) { _PendingDownloads.TryAdd(block, block); AttachedNode.SendMessageAsync(new GetDataPayload(new InventoryVector(AttachedNode.AddSupportedOptions(InventoryType.MSG_BLOCK), block))); } }
void AttachedNode_StateChanged(Node node, NodeState oldState) { //TODO: to check: don't send to self if (node.State == NodeState.HandShaked && IsTipOld) { AttachedNode.SendMessageAsync(new GetTipPayload()); } }
//Caller should add to the puller map internal void StartDownload(GetDataPayload getDataPayload) { foreach (var inv in getDataPayload.Inventory) { inv.Type = AttachedNode.AddSupportedOptions(inv.Type); _PendingDownloads.TryAdd(inv.Hash, inv.Hash); } AttachedNode.SendMessageAsync(getDataPayload); }
private void BroadcastCore(Transaction obj) { if (_Builder.Broadcast) { if (_Filter != null && _Filter.IsRelevantAndUpdate(obj) && _Known.TryAdd(obj.GetHash(), obj.GetHash())) { AttachedNode.SendMessageAsync(new InvPayload(obj)); } } }
void _Builder_NewTransaction(Transaction obj) { _Transactions.AddOrReplace(obj.GetHash(), obj); if (_Builder.Broadcast) { if (_Filter != null && _Filter.IsRelevantAndUpdate(obj) && _Known.TryAdd(obj.GetHash(), obj.GetHash())) { AttachedNode.SendMessageAsync(new InvPayload(obj)); } } }
/// <summary> /// Asynchronously try to sync the chain /// </summary> public void TrySync() { if (AttachedNode.State == NodeState.HandShaked && CanSync && !invalidHeaderReceived) { Interlocked.Increment(ref _SynchingCount); AttachedNode.SendMessageAsync(new GetHeadersPayload() { BlockLocators = GetPendingTip().GetLocator() }); } }
void _Builder_NewBlock(Block obj) { _Blocks.AddOrReplace(obj.GetHash(), obj); foreach (var tx in obj.Transactions) { _Transactions.TryAdd(tx.GetHash(), tx); } if (_Builder.Broadcast) { AttachedNode.SendMessageAsync(new InvPayload(obj)); } }
void AttachedNode_MessageReceived(Node node, IncomingMessage message) { var filterload = message.Message.Payload as FilterLoadPayload; if (filterload != null) { _Filter = filterload.Object; } var filteradd = message.Message.Payload as FilterAddPayload; if (filteradd != null) { _Filter.Insert(filteradd.Data); } var getdata = message.Message.Payload as GetDataPayload; if (getdata != null) { foreach (var inv in getdata.Inventory) { if (inv.Type == InventoryType.MSG_FILTERED_BLOCK && _Filter != null) { var merkle = new MerkleBlock(_Blocks[inv.Hash], _Filter); AttachedNode.SendMessageAsync(new MerkleBlockPayload(merkle)); foreach (var tx in merkle.PartialMerkleTree.GetMatchedTransactions()) { if (_Known.TryAdd(tx, tx)) { AttachedNode.SendMessageAsync(new InvPayload(InventoryType.MSG_TX, tx)); } } } var found = FindTransaction(inv.Hash); if (inv.Type == InventoryType.MSG_TX && found != null) { AttachedNode.SendMessageAsync(new TxPayload(found)); } } } var mempool = message.Message.Payload as MempoolPayload; if (mempool != null) { foreach (var tx in _Builder.Mempool) { BroadcastCore(tx.Value); } } }
public void AskBlocks() { if (AttachedNode.State != NodeState.HandShaked) { return; } var pendingTip = AttachedNode.Behaviors.Find <ChainBehavior>().PendingTip; if (pendingTip == null || pendingTip.Height < AttachedNode.PeerVersion.StartHeight) { return; } if (_InFlights.Count != 0) { return; } var currentLocation = _CurrentLocation ?? new BlockLocator() { Blocks = { Chain.GetBlock(StartHeight).HashBlock } };; var currentBlock = Chain.FindFork(currentLocation); if (currentBlock.Height < StartHeight) { currentBlock = Chain.GetBlock(StartHeight) ?? pendingTip; } //Up to date if (pendingTip.HashBlock == currentBlock.HashBlock) { return; } var toDownload = pendingTip.EnumerateToGenesis().TakeWhile(b => b.HashBlock != currentBlock.HashBlock).ToArray(); Array.Reverse(toDownload); var invs = toDownload.Take(10) .Select(b => new InventoryVector(AttachedNode.AddSupportedOptions(InventoryType.MSG_BLOCK), b.HashBlock)) .Where(b => _InFlights.TryAdd(b.Hash, new Download())) .ToArray(); if (invs.Length != 0) { AttachedNode.SendMessageAsync(new GetDataPayload(invs)); Runtime.Repository.SetIndexProgress(currentLocation); } }
protected override void AttachCore() { _Refresh = new Timer(o => { TrySync(); }, null, 0, (int)TimeSpan.FromMinutes(10).TotalMilliseconds); RegisterDisposable(_Refresh); if (AttachedNode.State == NodeState.Connected) { AttachedNode.MyVersion.StartHeight = Chain.Height; } AttachedNode.StateChanged += AttachedNode_StateChanged; RegisterDisposable(AttachedNode.Filters.Add(Intercept)); if (AttachedNode.State == NodeState.HandShaked) { AttachedNode.SendMessageAsync(new SendHeadersPayload()); TrySync(); } }
void AttachedNode_MessageReceived(Node node, IncomingMessage message) { var filterload = message.Message.Payload as FilterLoadPayload; if (filterload != null) { _Filter = filterload.Object; } var filteradd = message.Message.Payload as FilterAddPayload; if (filteradd != null) { _Filter.Insert(filteradd.Data); } var getdata = message.Message.Payload as GetDataPayload; if (getdata != null) { foreach (var inv in getdata.Inventory) { if (inv.Type == InventoryType.MSG_FILTERED_BLOCK && _Filter != null) { var merkle = new MerkleBlock(_Blocks[inv.Hash], _Filter); AttachedNode.SendMessageAsync(new MerkleBlockPayload(merkle)); foreach (var tx in merkle.PartialMerkleTree.GetMatchedTransactions()) { if (_Known.TryAdd(tx, tx)) { AttachedNode.SendMessageAsync(new InvPayload(InventoryType.MSG_TX, tx)); } } } var found = FindTransaction(inv.Hash); if (inv.Type == InventoryType.MSG_TX && found != null) { AttachedNode.SendMessageAsync(new TxPayload(found)); } } } var mempool = message.Message.Payload as MempoolPayload; if (mempool != null) { foreach (var tx in _Builder.Mempool) { BroadcastCore(tx.Value); } } var invs = message.Message.Payload as InvPayload; if (invs != null) { node.SendMessageAsync(new GetDataPayload(invs.ToArray())); } var txPayload = message.Message.Payload as TxPayload; if (txPayload != null) { if (!_ReceivedTransactions.TryAdd(txPayload.Object.GetHash(), txPayload.Object)) { node.SendMessageAsync(new RejectPayload() { Hash = txPayload.Object.GetHash(), Code = RejectCode.DUPLICATE, Message = "tx" }); } else { foreach (var other in Nodes.Where(n => n != node)) { other.SendMessageAsync(new InvPayload(txPayload.Object)); } } } }
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(); }
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) && !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) { HeadersPayload headers = new HeadersPayload(); var fork = Chain.FindFork(getheaders.BlockLocators); if (fork != null) { foreach (var header in Chain.EnumerateToTip(fork).Skip(1)) { 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 = GetPendingTip(); if (newheaders != null && CanSync) { var tip = GetPendingTip(); foreach (var header in newheaders.Headers) { var prev = tip.FindAncestorOrSelf(header.HashPrevBlock); if (prev == null) { break; } tip = new ChainedBlock(header, header.GetHash(), prev); if (!AttachedNode.IsTrusted) { var validated = Chain.GetBlock(tip.HashBlock) != null || tip.Validate(AttachedNode.Network); if (!validated) { invalidHeaderReceived = true; break; } } _PendingTip = tip; } if (_PendingTip.Height > Chain.Tip.Height) { 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 != GetPendingTip().HashBlock) { TrySync(); } Interlocked.Decrement(ref _SynchingCount); } act(); }