Exemple #1
0
        /// <summary>
        /// If there are any more blocks the node wants to download, this method assigns and starts
        /// a new download task for a specific peer that this behavior represents.
        /// </summary>
        private async Task AssignPendingVectorAsync()
        {
            this.logger.LogTrace("()");

            INetworkPeer attachedNode = this.AttachedPeer;

            if ((attachedNode == null) || (attachedNode.State != NetworkPeerState.HandShaked) || !this.puller.Requirements.Check(attachedNode.PeerVersion))
            {
                this.logger.LogTrace("(-)[ATTACHED_NODE]");
                return;
            }

            uint256 block = null;

            if (this.puller.AssignPendingDownloadTaskToPeer(this, out block))
            {
                try
                {
                    var getDataPayload = new GetDataPayload(new InventoryVector(attachedNode.AddSupportedOptions(InventoryType.MSG_BLOCK), block));
                    await attachedNode.SendMessageAsync(getDataPayload).ConfigureAwait(false);
                }
                catch (OperationCanceledException)
                {
                }
            }

            this.logger.LogTrace("(-)");
        }
Exemple #2
0
        /// <summary>
        /// Sends a message to the connected peer requesting specific data.
        /// </summary>
        /// <param name="getDataPayload">Specification of the data to download - <see cref="GetDataPayload"/>.</param>
        /// <returns><c>true</c> if the message was successfully sent to the peer, <c>false</c> if the peer got disconnected.</returns>
        /// <remarks>Caller is responsible to add the puller to the map if necessary.</remarks>
        internal async Task <bool> StartDownloadAsync(GetDataPayload getDataPayload)
        {
            this.logger.LogTrace("()");

            INetworkPeer attachedNode = this.AttachedPeer;

            if ((attachedNode == null) || (attachedNode.State != NetworkPeerState.HandShaked) || !this.puller.Requirements.Check(attachedNode.PeerVersion))
            {
                this.logger.LogTrace("(-)[ATTACHED_PEER]:false");
                return(false);
            }

            foreach (InventoryVector inv in getDataPayload.Inventory)
            {
                inv.Type = attachedNode.AddSupportedOptions(inv.Type);
            }

            try
            {
                await attachedNode.SendMessageAsync(getDataPayload).ConfigureAwait(false);

                // In case job is assigned to a peer with low quality score-
                // give it enough score so the job is not reassigned right away.
                this.UpdateQualityScore(BlockPulling.QualityScore.MaxScore / 10);
            }
            catch (OperationCanceledException)
            {
                this.logger.LogTrace("(-)[CANCELLED]:false");
                return(false);
            }

            this.logger.LogTrace("(-):true");
            return(true);
        }
Exemple #3
0
        private void StartDownload(InventoryVector[] vectors, BlockingPullerBehavior[] nodes)
        {
            if (vectors.Length == 0)
            {
                return;
            }

            if (nodes.Length == 0)
            {
                foreach (var v in vectors)
                {
                    this.pendingInventoryVectors.Add(v.Hash);
                }
                return;
            }

            // find the node with the height score
            var selected = nodes.OrderByDescending(n => n.QualityScore).First();
            var getdata  = new GetDataPayload();

            foreach (var inv in vectors)
            {
                if (this.map.TryAdd(inv.Hash, selected))
                {
                    getdata.Inventory.Add(inv);
                }
            }
            selected.StartDownload(getdata);
        }
        public static async Task <Block> DownloadBlockAsync(this Node node, uint256 hash, CancellationToken cancellationToken)
        {
            if (node.State == NodeState.Connected)
            {
                node.VersionHandshake(cancellationToken);
            }

            using var listener = node.CreateListener();
            var getdata = new GetDataPayload(new InventoryVector(node.AddSupportedOptions(InventoryType.MSG_BLOCK), hash));
            await node.SendMessageAsync(getdata).ConfigureAwait(false);

            cancellationToken.ThrowIfCancellationRequested();

            // Bitcoin Core processes the messages sequentially and does not send a NOTFOUND message if the remote node is pruned and the data not available.
            // A good way to get any feedback about whether the node knows the block or not is to send a ping request.
            // If block is not known by the remote node, the pong will be sent immediately, else it will be sent after the block download.
            ulong pingNonce = RandomUtils.GetUInt64();
            await node.SendMessageAsync(new PingPayload()
            {
                Nonce = pingNonce
            }).ConfigureAwait(false);

            while (true)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var message = listener.ReceiveMessage(cancellationToken);
                if (message.Message.Payload is NotFoundPayload ||
                    (message.Message.Payload is PongPayload p && p.Nonce == pingNonce))
                {
                    throw new InvalidOperationException($"Disconnected local node, because it does not have the block data.");
                }
Exemple #5
0
        private async Task ProcessInvAsync(Node node, InvPayload invPayload)
        {
            if (invPayload.Inventory.Count > MAX_INV_SIZE)
            {
                Logger.LogDebug($"Received inventory too big. {nameof(MAX_INV_SIZE)}: {MAX_INV_SIZE}, Node: {node.RemoteSocketEndpoint}");
                return;
            }

            var payload = new GetDataPayload();

            foreach (var inv in invPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX)))
            {
                // if we already have it continue;
                if (!MemPoolService.TransactionHashes.Add(inv.Hash))
                {
                    continue;
                }

                payload.Inventory.Add(inv);
            }

            if (node.IsConnected)
            {
                // ask for the whole transaction
                await node.SendMessageAsync(payload);
            }
        }
Exemple #6
0
 private void AttachedNode_MessageReceived(Node node, IncomingMessage message)
 {
     if (message.Message.Payload is InvPayload invs)
     {
         // Do not asks transactions if we are synching so that we can process blocks faster
         if (IsSynching())
         {
             return;
         }
         var data = new GetDataPayload();
         foreach (var inv in invs.Inventory.Where(t => t.Type.HasFlag(InventoryType.MSG_TX)))
         {
             inv.Type = node.AddSupportedOptions(inv.Type);
             data.Inventory.Add(inv);
         }
         if (data.Inventory.Count != 0)
         {
             node.SendMessageAsync(data);
         }
     }
     else if (message.Message.Payload is HeadersPayload headers)
     {
         if (headers.Headers.Count == 0)
         {
             return;
         }
         _NewBlock.Set();
     }
     else if (message.Message.Payload is TxPayload txPayload)
     {
         Run(() => SaveMatches(txPayload.Object, true));
     }
 }
        /// <summary>
        /// Handler for processing node messages.
        /// Handles the following message payloads: TxPayload, MempoolPayload, GetDataPayload, InvPayload.
        /// </summary>
        /// <param name="node">Node sending the message.</param>
        /// <param name="message">Incoming message.</param>
        private Task AttachedNode_MessageReceivedAsync(Node node, IncomingMessage message)
        {
            TxPayload txPayload = message.Message.Payload as TxPayload;

            if (txPayload != null)
            {
                return(this.ProcessTxPayloadAsync(node, txPayload));
            }

            MempoolPayload mempoolPayload = message.Message.Payload as MempoolPayload;

            if (mempoolPayload != null)
            {
                return(this.SendMempoolPayload(node, mempoolPayload));
            }

            GetDataPayload getDataPayload = message.Message.Payload as GetDataPayload;

            if (getDataPayload != null)
            {
                return(this.ProcessGetDataAsync(node, getDataPayload));
            }

            InvPayload invPayload = message.Message.Payload as InvPayload;

            if (invPayload != null)
            {
                return(this.ProcessInvAsync(node, invPayload));
            }

            return(Task.CompletedTask);
        }
 private void AttachedNode_MessageReceived(Node node, IncomingMessage message)
 {
     if (message.Message.Payload is InvPayload invs)
     {
         var data = new GetDataPayload();
         foreach (var inv in invs.Inventory)
         {
             inv.Type = node.AddSupportedOptions(inv.Type);
             if (inv.Type.HasFlag(InventoryType.MSG_TX))
             {
                 data.Inventory.Add(inv);
             }
         }
         if (data.Inventory.Count != 0)
         {
             node.SendMessageAsync(data);
         }
     }
     else if (message.Message.Payload is HeadersPayload headers)
     {
         if (headers.Headers.Count == 0)
         {
             return;
         }
         AskBlocks();
     }
     else if (message.Message.Payload is BlockPayload block)
     {
         Task.Run(() => SaveMatches(block.Object));
     }
     else if (message.Message.Payload is TxPayload txPayload)
     {
         Task.Run(() => SaveMatches(txPayload.Object));
     }
 }
        /// <inheritdoc/>
        public async Task RequestBlocksAsync(List <uint256> hashes)
        {
            var getDataPayload = new GetDataPayload();

            INetworkPeer peer = this.AttachedPeer;

            if (peer == null)
            {
                this.logger.LogTrace("(-)[PEER_DETACHED]");
                throw new OperationCanceledException("Peer is detached already!");
            }

            foreach (uint256 uint256 in hashes)
            {
                var vector = new InventoryVector(InventoryType.MSG_BLOCK, uint256);
                vector.Type = peer.AddSupportedOptions(vector.Type);

                getDataPayload.Inventory.Add(vector);
            }

            if (peer.State != NetworkPeerState.HandShaked)
            {
                this.logger.LogTrace("(-)[ATTACHED_PEER]");
                throw new OperationCanceledException("Peer is in the wrong state!");
            }

            await peer.SendMessageAsync(getDataPayload).ConfigureAwait(false);
        }
        /// <summary>
        /// Processing of the get data payload message from node.
        /// Sends the memory pool transaction info via TxPayload to the attached node.
        /// </summary>
        /// <param name="node">Node sending the message.</param>
        /// <param name="getDataPayload">The payload for the message.</param>
        private async Task ProcessGetDataAsync(NetworkPeer node, GetDataPayload getDataPayload)
        {
            Guard.NotNull(node, nameof(node));
            this.logger.LogTrace("({0}:'{1}',{2}.{3}.{4}:{5})", nameof(node), node.RemoteSocketEndpoint, nameof(getDataPayload), nameof(getDataPayload.Inventory), nameof(getDataPayload.Inventory.Count), getDataPayload.Inventory.Count);
            if (node != this.AttachedPeer)
            {
                this.logger.LogDebug("Attached node '{0}' does not match the originating node '{1}'.", this.AttachedPeer?.RemoteSocketEndpoint, node.RemoteSocketEndpoint);
                this.logger.LogTrace("(-)[NODE_MISMATCH]");
                return;
            }

            foreach (InventoryVector item in getDataPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX)))
            {
                // TODO: check if we need to add support for "not found"

                TxMempoolInfo trxInfo = await this.manager.InfoAsync(item.Hash).ConfigureAwait(false);

                if (trxInfo != null)
                {
                    //TODO strip block of witness if node does not support
                    if (node.IsConnected)
                    {
                        this.logger.LogTrace("Sending transaction '{0}' to peer '{1}'.", item.Hash, node.RemoteSocketEndpoint);
                        await node.SendMessageAsync(new TxPayload(trxInfo.Trx.WithOptions(node.SupportedTransactionOptions))).ConfigureAwait(false);
                    }
                }
            }

            this.logger.LogTrace("(-)");
        }
Exemple #11
0
        private async Task ProcessInvAsync(Node node, InvPayload invPayload)
        {
            Guard.Assert(node == this.AttachedNode);             // just in case

            if (invPayload.Inventory.Count > ConnectionManager.MAX_INV_SZ)
            {
                //Misbehaving(pfrom->GetId(), 20); // TODO: Misbehaving
                return;                 //error("message inv size() = %u", vInv.size());
            }

            if (this.chainState.IsInitialBlockDownload)
            {
                return;
            }

            bool blocksOnly = !this.manager.NodeArgs.Mempool.RelayTxes;

            // Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true
            if (node.Behavior <ConnectionManagerBehavior>().Whitelisted&& this.manager.NodeArgs.Mempool.Whitelistrelay)
            {
                blocksOnly = false;
            }

            //uint32_t nFetchFlags = GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus());

            var send = new GetDataPayload();

            foreach (var inv in invPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX)))
            {
                //inv.type |= nFetchFlags;

                if (blocksOnly)
                {
                    Logging.Logs.Mempool.LogInformation(
                        $"transaction ({inv.Hash}) inv sent in violation of protocol peer={node.RemoteSocketEndpoint}");
                }

                if (await this.orphans.AlreadyHave(inv.Hash))
                {
                    continue;
                }

                send.Inventory.Add(inv);
            }

            // add to known inventory
            await this.manager.MempoolScheduler.WriteAsync(() =>
            {
                foreach (var inventoryVector in send.Inventory)
                {
                    this.filterInventoryKnown.TryAdd(inventoryVector.Hash, inventoryVector.Hash);
                }
            });

            if (node.IsConnected)
            {
                await node.SendMessageAsync(send).ConfigureAwait(false);
            }
        }
Exemple #12
0
        public void ConstructorTest()
        {
            var invs = new Inventory[2];
            var pl   = new GetDataPayload(invs);

            Assert.Equal(PayloadType.GetData, pl.PayloadType);
            Assert.Same(invs, pl.InventoryList);
        }
Exemple #13
0
        /// <summary>
        /// Processing of inventory payload message from the peer.
        /// Adds inventory to known inventory then sends GetDataPayload to the attached peer.
        /// </summary>
        /// <param name="peer">The peer sending the message.</param>
        /// <param name="invPayload">The inventory payload in the message.</param>
        private async Task ProcessInvAsync(INetworkPeer peer, InvPayload invPayload)
        {
            Guard.NotNull(peer, nameof(peer));
            this.logger.LogTrace("({0}:'{1}',{2}.{3}.{4}:{5})", nameof(peer), peer.RemoteSocketEndpoint, nameof(invPayload), nameof(invPayload.Inventory), nameof(invPayload.Inventory.Count), invPayload.Inventory.Count);

            if (invPayload.Inventory.Count > ConnectionManager.MaxInventorySize)
            {
                this.logger.LogTrace("(-)[MAX_INV_SZ]");
                //Misbehaving(pfrom->GetId(), 20); // TODO: Misbehaving
                return; //error("message inv size() = %u", vInv.size());
            }

            if (this.initialBlockDownloadState.IsInitialBlockDownload())
            {
                this.logger.LogTrace("(-)[IS_IBD]");
                return;
            }

            //uint32_t nFetchFlags = GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus());

            var send = new GetDataPayload();

            foreach (InventoryVector inv in invPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX)))
            {
                //inv.type |= nFetchFlags;

                // TODO: This is incorrect, in blocks only mode we should just add to known inventory but not relay
                if (this.isBlocksOnlyMode)
                {
                    this.logger.LogInformation("Transaction ID '{0}' inventory sent in violation of protocol peer '{1}'.", inv.Hash, peer.RemoteSocketEndpoint);
                }

                if (await this.orphans.AlreadyHaveAsync(inv.Hash))
                {
                    this.logger.LogDebug("Transaction ID '{0}' already in orphans, skipped.", inv.Hash);
                    continue;
                }

                send.Inventory.Add(inv);
            }

            // add to known inventory
            lock (this.lockObject)
            {
                foreach (InventoryVector inventoryVector in send.Inventory)
                {
                    this.filterInventoryKnown.Add(inventoryVector.Hash);
                }
            }

            if (peer.IsConnected)
            {
                this.logger.LogTrace("Sending transaction inventory to peer '{0}'.", peer.RemoteSocketEndpoint);
                await peer.SendMessageAsync(send).ConfigureAwait(false);
            }

            this.logger.LogTrace("(-)");
        }
Exemple #14
0
 //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);
 }
        void AttachedNode_MessageReceived(Node node, IncomingMessage message)
        {
            InvPayload invPayload = message.Message.Payload as InvPayload;

            if (invPayload != null)
            {
                foreach (var hash in invPayload.Where(i => i.Type == InventoryType.MSG_TX).Select(i => i.Hash))
                {
                    var tx = GetTransaction(hash, true);
                    if (tx != null)
                    {
                        tx.State = BroadcastState.Accepted;
                    }
                    Transaction unused;
                    if (_BroadcastHub.BroadcastedTransaction.TryRemove(hash, out unused))
                    {
                        _BroadcastHub.OnTransactionBroadcasted(tx.Transaction);
                    }
                }
            }

            GetDataPayload getData = message.Message.Payload as GetDataPayload;

            if (getData != null)
            {
                foreach (var inventory in getData.Inventory.Where(i => i.Type == InventoryType.MSG_TX))
                {
                    var tx = GetTransaction(inventory.Hash, false);
                    if (tx != null)
                    {
                        tx.State = BroadcastState.Broadcasted;
                        var ping = new PingPayload();
                        tx.PingValue = ping.Nonce;
                        _PingToTransaction.TryAdd(tx.PingValue, tx);
                        node.SendMessageAsync(new TxPayload(tx.Transaction));
                        node.SendMessageAsync(ping);
                    }
                }
            }

            PongPayload pong = message.Message.Payload as PongPayload;

            if (pong != null)
            {
                var tx = GetTransaction(pong.Nonce, true);
                if (tx != null)
                {
                    tx.State = BroadcastState.Accepted;
                    Transaction unused;
                    if (_BroadcastHub.BroadcastedTransaction.TryRemove(tx.Transaction.GetHash(), out unused))
                    {
                        _BroadcastHub.OnTransactionBroadcasted(tx.Transaction);
                    }
                }
            }
        }
        /// <summary>
        ///     Processing of inventory payload message from the peer.
        ///     Adds inventory to known inventory then sends GetDataPayload to the attached peer.
        /// </summary>
        /// <param name="peer">The peer sending the message.</param>
        /// <param name="invPayload">The inventory payload in the message.</param>
        async Task ProcessInvAsync(INetworkPeer peer, InvPayload invPayload)
        {
            Guard.NotNull(peer, nameof(peer));

            if (invPayload.Inventory.Count > ConnectionManager.MaxInventorySize)
            {
                this.logger.LogTrace("(-)[MAX_INV_SZ]");
                //Misbehaving(pfrom->GetId(), 20); // TODO: Misbehaving
                return; //error("message inv size() = %u", vInv.size());
            }

            if (this.initialBlockDownloadState.IsInitialBlockDownload())
            {
                this.logger.LogTrace("(-)[IS_IBD]");
                return;
            }

            //uint32_t nFetchFlags = GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus());

            var inventoryTxs = invPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX));

            lock (this.lockObject)
            {
                foreach (var inv in inventoryTxs)
                {
                    this.filterInventoryKnown.Add(inv.Hash);
                }
            }

            var send = new GetDataPayload();

            foreach (var inv in inventoryTxs)
            {
                if (await this.orphans.AlreadyHaveAsync(inv.Hash).ConfigureAwait(false))
                {
                    this.logger.LogDebug("Transaction ID '{0}' already in orphans, skipped.", inv.Hash);
                    continue;
                }

                if (this.isBlocksOnlyMode)
                {
                    this.logger.LogDebug("Transaction ID '{0}' inventory sent in violation of protocol peer '{1}'.",
                                         inv.Hash, peer.RemoteSocketEndpoint);
                    continue;
                }

                send.Inventory.Add(new InventoryVector(peer.AddSupportedOptions(InventoryType.MSG_TX), inv.Hash));
            }

            if (peer.IsConnected && send.Inventory.Count > 0)
            {
                this.logger.LogDebug("Asking for transaction data from peer '{0}'.", peer.RemoteSocketEndpoint);
                await peer.SendMessageAsync(send).ConfigureAwait(false);
            }
        }
        private void DistributeDownload(InventoryVector[] vectors, BlockPullerBehavior[] innernodes, int minHight)
        {
            if (vectors.Length == 0)
            {
                return;
            }

            // Be careful to not ask block to a node that do not have it
            // (we can check the ChainHeadersBehavior.PendingTip to know where the node is standing)
            var selectnodes = new List <BlockPullerBehavior>();

            foreach (BlockPullerBehavior behavior in innernodes)
            {
                // filter nodes that are still behind using the
                // pending tip in the chain behaviour
                if (behavior.ChainHeadersBehavior?.PendingTip?.Height >= minHight)
                {
                    selectnodes.Add(behavior);
                }
            }
            innernodes = selectnodes.ToArray();

            if (innernodes.Length == 0)
            {
                foreach (InventoryVector v in vectors)
                {
                    this.pendingInventoryVectors.Add(v.Hash);
                }
                return;
            }

            int[] scores     = innernodes.Select(n => n.QualityScore == MaxQualityScore ? MaxQualityScore * 2 : n.QualityScore).ToArray();
            var   totalScore = scores.Sum();

            GetDataPayload[] getDatas = innernodes.Select(n => new GetDataPayload()).ToArray();
            foreach (InventoryVector inv in vectors)
            {
                int index = GetNodeIndex(scores, totalScore);
                BlockPullerBehavior node    = innernodes[index];
                GetDataPayload      getData = getDatas[index];
                if (this.map.TryAdd(inv.Hash, node))
                {
                    getData.Inventory.Add(inv);
                }
            }
            for (int i = 0; i < innernodes.Length; i++)
            {
                if (getDatas[i].Inventory.Count == 0)
                {
                    continue;
                }
                innernodes[i].StartDownload(getDatas[i]);
            }
        }
Exemple #18
0
        async Task ProcessGetDataAsync(INetworkPeer peer, GetDataPayload getDataPayload)
        {
            // TODO: bring logic from core
            foreach (var item in getDataPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_BLOCK)))
            {
                var chainedHeaderBlock = this.consensusManager.GetBlockData(item.Hash);

                if (chainedHeaderBlock?.Block != null)
                {
                    this.logger.LogDebug("Sending block '{0}' to peer '{1}'.", chainedHeaderBlock.ChainedHeader,
                                         peer.RemoteSocketEndpoint);

                    //TODO strip block of witness if node does not support
                    await peer.SendMessageAsync(new BlockPayload(chainedHeaderBlock.Block.WithOptions(
                                                                     this.ChainIndexer.Network.Consensus.ConsensusFactory, peer.SupportedTransactionOptions)))
                    .ConfigureAwait(false);
                }
                else
                {
                    this.logger.LogDebug("Block with hash '{0}' requested from peer '{1}' was not found in store.",
                                         item.Hash, peer.RemoteSocketEndpoint);
                }

                // If the peer is syncing using "getblocks" message we are supposed to send
                // an "inv" message with our tip to it once it asks for all blocks
                // from the previous batch.
                if (item.Hash == this.getBlocksBatchLastItemHash)
                {
                    // Reset the hash to indicate that no continuation is pending anymore.
                    this.getBlocksBatchLastItemHash = null;

                    // Announce last block we have in the store.
                    var blockStoreTip = this.blockStoreQueue.BlockStoreCacheTip;
                    if (blockStoreTip != null)
                    {
                        this.logger.LogDebug("Sending continuation inventory message for block '{0}' to peer '{1}'.",
                                             blockStoreTip, peer.RemoteSocketEndpoint);
                        var invContinue = new InvPayload();
                        invContinue.Inventory.Add(new InventoryVector(InventoryType.MSG_BLOCK,
                                                                      blockStoreTip.HashBlock));
                        await peer.SendMessageAsync(invContinue).ConfigureAwait(false);
                    }
                    else
                    {
                        this.logger.LogDebug("Reorg in blockstore, inventory continuation won't be sent to peer '{0}'.",
                                             peer.RemoteSocketEndpoint);
                    }
                }
            }
        }
        private async Task ProcessInventoryAsync(Node node, InvPayload invPayload)
        {
            var getDataPayload = new GetDataPayload();

            foreach (var inv in invPayload.Inventory)
            {
                if (ProcessInventoryVector(inv, node.RemoteSocketEndpoint))
                {
                    getDataPayload.Inventory.Add(inv);
                }
            }
            if (getDataPayload.Inventory.Any() && node.IsConnected)
            {
                await node.SendMessageAsync(getDataPayload).ConfigureAwait(false);
            }
        }
        private async void AttachedNode_MessageReceivedAsync(Node node, IncomingMessage message)
        {
            try
            {
                if (message.Message.Payload is TxPayload txPayload)
                {
                    Transaction?.Invoke(this, new SmartTransaction(txPayload.Object, Height.Mempool));
                }
                else if (message.Message.Payload is BlockPayload blockPayload)
                {
                    Block?.Invoke(this, blockPayload.Object);
                }
                else if (message.Message.Payload is InvPayload invPayload)
                {
                    var getDataPayload = new GetDataPayload();
                    foreach (var inv in invPayload.Inventory)
                    {
                        if (inv.Type.HasFlag(InventoryType.MSG_TX))
                        {
                            TransactionInv?.Invoke(this, inv.Hash);
                            getDataPayload.Inventory.Add(inv);
                        }

                        if (inv.Type.HasFlag(InventoryType.MSG_BLOCK))
                        {
                            BlockInv?.Invoke(this, inv.Hash);
                            getDataPayload.Inventory.Add(inv);
                        }
                    }

                    if (getDataPayload.Inventory.Any() && node.IsConnected)
                    {
                        // ask for the whole transaction
                        await node.SendMessageAsync(getDataPayload).ConfigureAwait(false);
                    }
                }
            }
            catch (OperationCanceledException ex)
            {
                Logger.LogDebug(ex);
            }
            catch (Exception ex)
            {
                Logger.LogInfo($"Ignoring {ex.GetType()}: {ex.Message}");
                Logger.LogDebug(ex);
            }
        }
        protected async Task ProcessGetDataPayloadAsync(NetworkPeer peer, GetDataPayload getDataPayload)
        {
            // If node asks for tx we want to broadcast.
            foreach (InventoryVector inv in getDataPayload.Inventory.Where(x => x.Type == InventoryType.MSG_TX))
            {
                TransactionBroadcastEntry txEntry = this.broadcasterManager.GetTransaction(inv.Hash);
                if ((txEntry != null) && (txEntry.State != State.CantBroadcast))
                {
                    await peer.SendMessageAsync(new TxPayload(txEntry.Transaction)).ConfigureAwait(false);

                    if (txEntry.State == State.ToBroadcast)
                    {
                        this.broadcasterManager.AddOrUpdate(txEntry.Transaction, State.Broadcasted);
                    }
                }
            }
        }
		private async Task ProcessGetDataAsync(Node node, GetDataPayload getDataPayload)
		{
			Guard.Assert(node != null); 

			// TODO: bring logic from core 
			foreach (var item in getDataPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_BLOCK)))
			{
				// TODO: check if we need to add support for "not found" 

				var block = await this.blockStoreCache.GetBlockAsync(item.Hash).ConfigureAwait(false);


				if (block != null)
					//TODO strip block of witness if node does not support
					await node.SendMessageAsync(new BlockPayload(block.WithOptions(node.SupportedTransactionOptions))).ConfigureAwait(false);
			}
		}
        private async void AttachedNode_MessageReceivedAsync(Node node, IncomingMessage message)
        {
            try
            {
                if (message.Message.Payload is InvPayload invPayload)
                {
                    var payload = new GetDataPayload();
                    foreach (var inv in invPayload.Inventory)
                    {
                        if (inv.Type.HasFlag(InventoryType.MSG_TX))
                        {
                            TransactionInv?.Invoke(this, inv.Hash);
                            payload.Inventory.Add(inv);
                        }
                        else if (inv.Type.HasFlag(InventoryType.MSG_BLOCK))
                        {
                            BlockInv?.Invoke(this, inv.Hash);
                            payload.Inventory.Add(inv);
                        }
                    }

                    if (payload.Inventory.Any() && node.IsConnected)
                    {
                        // ask for the whole transaction
                        await node.SendMessageAsync(payload);
                    }
                }
                else if (message.Message.Payload is TxPayload txPayload)
                {
                    Transaction?.Invoke(this, txPayload.Object);
                }
                else if (message.Message.Payload is BlockPayload blockPayload)
                {
                    Block?.Invoke(this, blockPayload.Object);
                }
            }
            catch (OperationCanceledException ex)
            {
                Logger.LogDebug <TrustedNodeNotifyingBehavior>(ex);
            }
            catch (Exception ex)
            {
                Logger.LogInfo <TrustedNodeNotifyingBehavior>($"Ignoring {ex.GetType()}: {ex.Message}");
                Logger.LogDebug <TrustedNodeNotifyingBehavior>(ex);
            }
        }
Exemple #24
0
        private GetDataPayload CreateGetDataPayload(IEnumerable <uint256> hashes)
        {
            var message = new GetDataPayload();

            foreach (var hash in hashes)
            {
                if (!this.blockSyncHub.ChainIndex.Contains(hash))
                {
                    message.Inventory.Add(new InventoryVector()
                    {
                        Type = InventoryType.MSG_BLOCK,
                        Hash = hash
                    });
                }
            }

            return(message);
        }
        private async Task ProcessGetDataAsync(INetworkPeer peer, GetDataPayload getDataPayload)
        {
            this.logger.LogTrace("({0}:'{1}',{2}.{3}.{4}:{5})", nameof(peer), peer.RemoteSocketEndpoint, nameof(getDataPayload), nameof(getDataPayload.Inventory), nameof(getDataPayload.Inventory.Count), getDataPayload.Inventory.Count);

            // TODO: bring logic from core
            foreach (InventoryVector item in getDataPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_BLOCK)))
            {
                // TODO: check if we need to add support for "not found"
                Block block = await this.blockStoreCache.GetBlockAsync(item.Hash).ConfigureAwait(false);

                if (block != null)
                {
                    this.logger.LogTrace("Sending block '{0}' to peer '{1}'.", item.Hash, peer.RemoteSocketEndpoint);

                    //TODO strip block of witness if node does not support
                    await peer.SendMessageAsync(new BlockPayload(block.WithOptions(this.chain.Network.Consensus.ConsensusFactory, peer.SupportedTransactionOptions))).ConfigureAwait(false);
                }

                // If the peer is syncing using "getblocks" message we are supposed to send
                // an "inv" message with our tip to it once it asks for all blocks
                // from the previous batch.
                if (item.Hash == this.getBlocksBatchLastItemHash)
                {
                    // Reset the hash to indicate that no continuation is pending anymore.
                    this.getBlocksBatchLastItemHash = null;

                    // Announce last block we have in the store.
                    ChainedHeader blockStoreTip = this.chain.GetBlock(this.blockRepository.BlockHash);
                    if (blockStoreTip != null)
                    {
                        this.logger.LogTrace("Sending continuation inventory message for block '{0}' to peer '{1}'.", blockStoreTip, peer.RemoteSocketEndpoint);
                        var invContinue = new InvPayload();
                        invContinue.Inventory.Add(new InventoryVector(InventoryType.MSG_BLOCK, blockStoreTip.HashBlock));
                        await peer.SendMessageAsync(invContinue).ConfigureAwait(false);
                    }
                    else
                    {
                        this.logger.LogTrace("Reorg in blockstore, inventory continuation won't be sent to peer '{0}'.", peer.RemoteSocketEndpoint);
                    }
                }
            }

            this.logger.LogTrace("(-)");
        }
Exemple #26
0
        private async Task ProcessInvAsync(Node node, InvPayload payload)
        {
            if (payload.Inventory.Count > MaxInvSize)
            {
                Logger.LogDebug($"Received inventory too big. {nameof(MaxInvSize)}: {MaxInvSize}, Node: {node.RemoteSocketEndpoint}");
                return;
            }

            var getDataPayload = new GetDataPayload();

            foreach (var inv in payload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX)))
            {
                if (MempoolService.TryGetFromBroadcastStore(inv.Hash, out TransactionBroadcastEntry entry))                 // If we have the transaction then adjust confirmation.
                {
                    try
                    {
                        if (entry.NodeRemoteSocketEndpoint == node.RemoteSocketEndpoint.ToString())
                        {
                            continue;                             // Wtf, why are you trying to broadcast it back to us?
                        }

                        entry.ConfirmPropagationOnce();
                    }
                    catch (Exception ex)
                    {
                        Logger.LogInfo(ex);
                    }
                }

                // if we already processed it continue;
                if (MempoolService.IsProcessed(inv.Hash))
                {
                    continue;
                }

                getDataPayload.Inventory.Add(inv);
            }

            if (getDataPayload.Inventory.Any() && node.IsConnected)
            {
                // ask for the whole transaction
                await node.SendMessageAsync(getDataPayload).ConfigureAwait(false);
            }
        }
Exemple #27
0
        void StartScan(object unused)
        {
            var node = AttachedNode;

            if (_RunningPing != null)
            {
                _PlannedScan = true;
                return;
            }
            if (!IsScanning(node))
            {
                if (Monitor.TryEnter(cs))
                {
                    try
                    {
                        if (!IsScanning(node))
                        {
                            GetDataPayload payload = new GetDataPayload();
                            var            fork    = _Chain.FindFork(_CurrentProgress);
                            foreach (var block in _Chain
                                     .EnumerateAfter(fork)
                                     .Where(b => b.Header.BlockTime + TimeSpan.FromHours(5.0) > _SkipBefore)                            //Take 5 more hours, block time might not be right
                                     .Partition(10000)
                                     .FirstOrDefault() ?? new List <ChainedBlock>())
                            {
                                if (block.HashBlock != _LastSeen)
                                {
                                    payload.Inventory.Add(new InventoryVector(InventoryType.MSG_FILTERED_BLOCK, block.HashBlock));
                                    _InFlight.TryAdd(block.HashBlock, block.HashBlock);
                                }
                            }
                            if (payload.Inventory.Count > 0)
                            {
                                node.SendMessageAsync(payload);
                            }
                        }
                    }
                    finally
                    {
                        Monitor.Exit(cs);
                    }
                }
            }
        }
Exemple #28
0
        private void RespondToGetDataPayload(Node node, GetDataPayload getDataPayload)
        {
            this.blockSyncHub.GetDataItems.TryAdd(new HubGetDataItem
            {
                Behaviour = this,
                Payload   = getDataPayload,
                Node      = this.AttachedNode
            });

            RequestCounter requestCounter;

            foreach (var vector in getDataPayload.Inventory)
            {
                if (this.blockSyncHub.RequestCount.TryGetValue(vector.Hash, out requestCounter))
                {
                    Interlocked.Increment(ref requestCounter.Count);
                }
            }
        }
 protected void ProcessGetDataPayload(NetworkPeer node, GetDataPayload getDataPayload)
 {
     // if node asks for tx we want to broadcast
     foreach (var inv in getDataPayload.Inventory.Where(x => x.Type == InventoryType.MSG_TX))
     {
         var txEntry = this.manager.GetTransaction(inv.Hash);
         if (txEntry != null)
         {
             if (txEntry.State != State.CantBroadcast)
             {
                 node.SendMessage(new TxPayload(txEntry.Transaction));
                 if (txEntry.State == State.ToBroadcast)
                 {
                     this.manager.AddOrUpdate(txEntry.Transaction, State.Broadcasted);
                 }
             }
         }
     }
 }
        /// <summary>
        /// Processing of the get data payload message from the peer.
        /// Sends the memory pool transaction info via TxPayload to the attached peer.
        /// </summary>
        /// <param name="peer">Peer sending the message.</param>
        /// <param name="getDataPayload">The payload for the message.</param>
        private async Task ProcessGetDataAsync(INetworkPeer peer, GetDataPayload getDataPayload)
        {
            Guard.NotNull(peer, nameof(peer));

            foreach (InventoryVector item in getDataPayload.Inventory.Where(inv => inv.Type.HasFlag(InventoryType.MSG_TX)))
            {
                // TODO: check if we need to add support for "not found"

                TxMempoolInfo trxInfo = await this.mempoolManager.InfoAsync(item.Hash).ConfigureAwait(false);

                if (trxInfo != null)
                {
                    if (peer.IsConnected)
                    {
                        this.logger.LogDebug("Sending transaction '{0}' to peer '{1}'.", item.Hash, peer.RemoteSocketEndpoint);
                        await peer.SendMessageAsync(new TxPayload(trxInfo.Trx.WithOptions(peer.SupportedTransactionOptions, this.network.Consensus.ConsensusFactory))).ConfigureAwait(false);
                    }
                }
            }
        }