Пример #1
0
        private void OnGetDataMessageReceived(InvPayload payload)
        {
            foreach (UInt256 hash in payload.Hashes.Distinct())
            {
                IInventory inventory;
                if (!localNode.RelayCache.TryGet(hash, out inventory) && !localNode.ServiceEnabled)
                {
                    continue;
                }
                switch (payload.Type)
                {
                case InventoryType.TX:
                    if (inventory == null)
                    {
                        inventory = LocalNode.GetTransaction(hash);
                    }
                    if (inventory == null && Blockchain.Default != null)
                    {
                        inventory = Blockchain.Default.GetTransaction(hash);
                    }
                    if (inventory != null)
                    {
                        EnqueueMessage("tx", inventory);
                    }
                    break;

                case InventoryType.Block:
                    if (inventory == null && Blockchain.Default != null)
                    {
                        inventory = Blockchain.Default.GetBlock(hash);
                    }
                    if (inventory != null)
                    {
                        BloomFilter filter = bloom_filter;
                        if (filter == null)
                        {
                            EnqueueMessage("block", inventory);
                        }
                        else
                        {
                            Block    block = (Block)inventory;
                            BitArray flags = new BitArray(block.Transactions.Select(p => TestFilter(filter, p)).ToArray());
                            EnqueueMessage("merkleblock", MerkleBlockPayload.Create(block, flags));
                        }
                    }
                    break;

                case InventoryType.Consensus:
                    if (inventory != null)
                    {
                        EnqueueMessage("consensus", inventory);
                    }
                    break;
                }
            }
        }
Пример #2
0
        private bool OnBroadcastCommand(string[] args)
        {
            string        command = args[1].ToLower();
            ISerializable payload = null;

            switch (command)
            {
            case "addr":
                payload = AddrPayload.Create(NetworkAddressWithTime.Create(new IPEndPoint(IPAddress.Parse(args[2]), ushort.Parse(args[3])), NetworkAddressWithTime.NODE_NETWORK, DateTime.UtcNow.ToTimestamp()));
                break;

            case "block":
                if (args[2].Length == 64 || args[2].Length == 66)
                {
                    payload = Blockchain.Default.GetBlock(UInt256.Parse(args[2]));
                }
                else
                {
                    payload = Blockchain.Default.GetBlock(uint.Parse(args[2]));
                }
                break;

            case "getblocks":
            case "getheaders":
                payload = GetBlocksPayload.Create(UInt256.Parse(args[2]));
                break;

            case "getdata":
            case "inv":
                payload = InvPayload.Create(Enum.Parse <InventoryType>(args[2], true), args.Skip(3).Select(UInt256.Parse).ToArray());
                break;

            case "tx":
                payload = LocalNode.GetTransaction(UInt256.Parse(args[2])) ?? Blockchain.Default.GetTransaction(UInt256.Parse(args[2]));
                break;

            case "alert":
            case "consensus":
            case "filteradd":
            case "filterload":
            case "headers":
            case "merkleblock":
            case "ping":
            case "pong":
            case "reject":
            case "verack":
            case "version":
                Console.WriteLine($"Command \"{command}\" is not supported.");
                return(true);
            }
            foreach (RemoteNode node in LocalNode.GetRemoteNodes())
            {
                node.EnqueueMessage(command, payload);
            }
            return(true);
        }
Пример #3
0
        public void DeserializeAndSerialize()
        {
            var test  = InvPayload.Create(InventoryType.TX, UInt256.Zero, UInt256.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00a4"));
            var clone = test.ToArray().AsSerializable <InvPayload>();

            Assert.AreEqual(test.Type, clone.Type);
            CollectionAssert.AreEqual(test.Hashes, clone.Hashes);

            Assert.ThrowsException <FormatException>(() => InvPayload.Create((InventoryType)0xff, UInt256.Zero).ToArray().AsSerializable <InvPayload>());
        }
Пример #4
0
        public void TryDeserialize_0Count_Test()
        {
            var  pl      = new InvPayload();
            var  stream  = new FastStreamReader(new byte[1]);
            bool success = pl.TryDeserialize(stream, out string error);

            Assert.True(success, error);
            Assert.Null(error);
            Assert.Empty(pl.InventoryList);
        }
Пример #5
0
        void NewNodeMessage(IncomingMessage message)
        {
            if (message.Message.Payload is VerAckPayload)
            {
                _Nodes.Add(message.Node);
            }
            if (message.Message.Payload is InvPayload)
            {
                InvPayload invPayload = (InvPayload)message.Message.Payload;
                message.Node.SendMessage(new GetDataPayload(invPayload.Inventory.ToArray()));
            }
            if (message.Message.Payload is TxPayload)
            {
                TxPayload txPayload = (TxPayload)message.Message.Payload;
                _ReceivedTransactions.AddOrUpdate(txPayload.Object.GetHash(), txPayload.Object, (k, v) => v);
            }
            if (message.Message.Payload is GetHeadersPayload)
            {
                var headers  = (GetHeadersPayload)message.Message.Payload;
                var fork     = _Server.ChainBuilder.Chain.FindFork(headers.BlockLocators);
                var response =
                    _Server.ChainBuilder.Chain
                    .ToEnumerable(true)
                    .TakeWhile(f => f.HashBlock != fork.HashBlock && f.HashBlock != headers.HashStop)
                    .Select(f => f.Header)
                    .ToArray();
                HeadersPayload res = new HeadersPayload();
                res.Headers.AddRange(response);
                message.Node.SendMessage(res);
            }

            if (message.Message.Payload is GetDataPayload)
            {
                Transaction tx;
                Block       block;
                var         getData = message.Message.Payload as GetDataPayload;
                foreach (var inv in getData.Inventory)
                {
                    if (inv.Type == InventoryType.MSG_TX)
                    {
                        if (_Transactions.TryGetValue(inv.Hash, out tx))
                        {
                            message.Node.SendMessage(new TxPayload(tx));
                        }
                    }
                    if (inv.Type == InventoryType.MSG_BLOCK)
                    {
                        if (_Blocks.TryGetValue(inv.Hash, out block))
                        {
                            message.Node.SendMessage(new BlockPayload(block));
                        }
                    }
                }
            }
        }
        private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest message)
        {
            Log($"{nameof(OnPrepareRequestReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} tx={message.TransactionHashes.Length}");
            if (!context.State.HasFlag(ConsensusState.Backup) || context.State.HasFlag(ConsensusState.RequestReceived))
            {
                return;
            }
            if (payload.ValidatorIndex != context.PrimaryIndex)
            {
                return;
            }
            if (payload.Timestamp <= Blockchain.Default.GetHeader(context.PrevHash).Timestamp || payload.Timestamp > DateTime.Now.AddMinutes(10).ToTimestamp())
            {
                Log($"Timestamp incorrect: {payload.Timestamp}");
                return;
            }
            context.State            |= ConsensusState.RequestReceived;
            context.Timestamp         = payload.Timestamp;
            context.Nonce             = message.Nonce;
            context.NextConsensus     = message.NextConsensus;
            context.TransactionHashes = message.TransactionHashes;
            context.Transactions      = new Dictionary <UInt256, Transaction>();
            if (!Crypto.Default.VerifySignature(context.MakeHeader().GetHashData(), message.Signature, context.Validators[payload.ValidatorIndex].EncodePoint(false)))
            {
                return;
            }
            context.Signatures = new byte[context.Validators.Length][];
            context.Signatures[payload.ValidatorIndex] = message.Signature;
            Dictionary <UInt256, Transaction> mempool = LocalNode.GetMemoryPool().ToDictionary(p => p.Hash);

            foreach (UInt256 hash in context.TransactionHashes.Skip(1))
            {
                if (mempool.TryGetValue(hash, out Transaction tx))
                {
                    if (!AddTransaction(tx, false))
                    {
                        return;
                    }
                }
            }
            if (!AddTransaction(message.MinerTransaction, true))
            {
                return;
            }
            if (context.Transactions.Count < context.TransactionHashes.Length)
            {
                UInt256[] hashes = context.TransactionHashes.Where(i => !context.Transactions.ContainsKey(i)).ToArray();
                LocalNode.AllowHashes(hashes);
                InvPayload msg = InvPayload.Create(InventoryType.TX, hashes);
                foreach (RemoteNode node in localNode.GetRemoteNodes())
                {
                    node.EnqueueMessage("getdata", msg);
                }
            }
        }
Пример #7
0
 private void InitializeConsensus(byte view_number)
 {
     lock (context)
     {
         if (view_number == 0)
         {
             context.Reset(wallet);
         }
         else
         {
             context.ChangeView(view_number);
         }
         if (context.MyIndex < 0)
         {
             return;
         }
         Log($"initialize: height={context.BlockIndex} view={view_number} index={context.MyIndex} role={(context.MyIndex == context.PrimaryIndex ? ConsensusState.Primary : ConsensusState.Backup)}");
         if (context.MyIndex == context.PrimaryIndex)
         {
             context.State |= ConsensusState.Primary;
             if (!context.State.HasFlag(ConsensusState.SignatureSent))
             {
                 FillContext();
             }
             if (context.TransactionHashes.Length > 1)
             {
                 InvPayload invPayload = InvPayload.Create(InventoryType.TX, context.TransactionHashes.Skip(1).ToArray());
                 foreach (RemoteNode node in localNode.GetRemoteNodes())
                 {
                     node.EnqueueMessage("inv", invPayload);
                 }
             }
             timer_height = context.BlockIndex;
             timer_view   = view_number;
             // 议长发起共识时间控制
             TimeSpan span = DateTime.Now - block_received_time;
             if (span >= Blockchain.TimePerBlock)
             {
                 timer.Change(0, Timeout.Infinite);// 间隔时间大于预订时间则立即发起共识
             }
             else
             {
                 timer.Change(Blockchain.TimePerBlock - span, Timeout.InfiniteTimeSpan);// 定时执行
             }
         }
         else
         {
             context.State = ConsensusState.Backup;
             timer_height  = context.BlockIndex;
             timer_view    = view_number;
             // 议员超时控制 t * 2 ^ (view_number + 1)
             timer.Change(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (view_number + 1)), Timeout.InfiniteTimeSpan);
         }
     }
 }
Пример #8
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>
        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);
            }
        }
Пример #9
0
        /// <summary>
        /// Sends transaction to peers.
        /// </summary>
        /// <param name="transaction">Transaction that will be propagated.</param>
        /// <param name="peers">Peers to whom we will propagate the transaction.</param>
        protected async Task PropagateTransactionToPeersAsync(Transaction transaction, List <NetworkPeer> peers)
        {
            this.AddOrUpdate(transaction, State.ToBroadcast);

            var invPayload = new InvPayload(transaction);

            foreach (var peer in peers)
            {
                await peer.SendMessageAsync(invPayload);
            }
        }
Пример #10
0
        private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest message)
        {
            Log($"{nameof(OnPrepareRequestReceived)}: height={payload.BlockIndex} view={message.ViewNumber} index={payload.ValidatorIndex} tx={message.TransactionHashes.Length}");
            if (!_context.State.HasFlag(ConsensusState.Backup) || _context.State.HasFlag(ConsensusState.RequestReceived))
            {
                return;
            }
            if (payload.ValidatorIndex != _context.PrimaryIndex)
            {
                return;
            }
            if (payload.Timestamp <= _context.Snapshot.GetHeader(_context.PrevHash).Timestamp || payload.Timestamp > DateTime.Now.AddMinutes(10).ToTimestamp())
            {
                Log($"Timestamp incorrect: {payload.Timestamp}", LogLevel.Warning);
                return;
            }
            _context.State            |= ConsensusState.RequestReceived;
            _context.Timestamp         = payload.Timestamp;
            _context.Nonce             = message.Nonce;
            _context.NextConsensus     = message.NextConsensus;
            _context.TransactionHashes = message.TransactionHashes;
            _context.Transactions      = new Dictionary <UInt256, Transaction>();
            if (!Crypto.Default.VerifySignature(_context.MakeHeader().GetHashData(), message.Signature, _context.Validators[payload.ValidatorIndex].EncodePoint(false)))
            {
                return;
            }
            _context.Signatures = new byte[_context.Validators.Length][];
            _context.Signatures[payload.ValidatorIndex] = message.Signature;
            Dictionary <UInt256, Transaction> mempool = Blockchain.Singleton.GetMemoryPool().ToDictionary(p => p.Hash);

            foreach (UInt256 hash in _context.TransactionHashes.Skip(1))
            {
                if (mempool.TryGetValue(hash, out Transaction tx))
                {
                    if (!AddTransaction(tx, false))
                    {
                        return;
                    }
                }
            }
            if (!AddTransaction(message.MinerTransaction, true))
            {
                return;
            }
            if (_context.Transactions.Count < _context.TransactionHashes.Length)
            {
                UInt256[] hashes = _context.TransactionHashes.Where(i => !_context.Transactions.ContainsKey(i)).ToArray();
                _system.TaskManager.Tell(new TaskManager.RestartTasks
                {
                    Payload = InvPayload.Create(InventoryType.Tx, hashes)
                });
            }
        }
Пример #11
0
        private void OnGetDataMessageReceived(Message msg)
        {
            InvPayload payload = msg.GetPayload <InvPayload>();

            if (sentHashes.Add(payload.Hashes[0]))
            {
                if (OnGetInventoryData(payload.Hashes[0], payload.Type))
                {
                    Context.Parent.Tell(RemoteNode.NewCounterMessage(RemoteNode.CounterType.Send, payload.Type, 1));
                }
            }
        }
Пример #12
0
 private void ProcessInvPayload(InvPayload invPayload)
 {
     // if node has transaction we broadcast
     foreach (InventoryVector inv in invPayload.Inventory.Where(x => x.Type == InventoryType.MSG_TX))
     {
         BroadcastTransactionStateChanedEntry txEntry = this.broadcasterManager.GetTransaction(inv.Hash);
         if (txEntry != null)
         {
             this.broadcasterManager.AddOrUpdate(txEntry.Transaction, TransactionBroadcastState.Propagated);
         }
     }
 }
Пример #13
0
 private void OnRestartTasks(InvPayload payload)
 {
     knownHashes.ExceptWith(payload.Hashes);
     foreach (UInt256 hash in payload.Hashes)
     {
         globalTasks.Remove(hash);
     }
     foreach (InvPayload group in InvPayload.CreateGroup(payload.Type, payload.Hashes))
     {
         system.LocalNode.Tell(Message.Create(MessageCommand.GetData, group));
     }
 }
 private void ProcessInvPayload(InvPayload invPayload)
 {
     // if node has tx we broadcasted
     foreach (var inv in invPayload.Inventory.Where(x => x.Type == InventoryType.MSG_TX))
     {
         var txEntry = this.manager.GetTransaction(inv.Hash);
         if (txEntry != null)
         {
             this.manager.AddOrUpdate(txEntry.Transaction, State.Propagated);
         }
     }
 }
Пример #15
0
 private void RequestTasks(TaskSession session)
 {
     if (session.HasTask)
     {
         return;
     }
     if (session.AvailableTasks.Count > 0)
     {
         session.AvailableTasks.ExceptWith(knownHashes);
         session.AvailableTasks.RemoveWhere(p => Blockchain.Singleton.ContainsBlock(p));
         HashSet <UInt256> hashes = new HashSet <UInt256>(session.AvailableTasks);
         if (hashes.Count > 0)
         {
             foreach (UInt256 hash in hashes.ToArray())
             {
                 if (!IncrementGlobalTask(hash))
                 {
                     hashes.Remove(hash);
                 }
             }
             session.AvailableTasks.ExceptWith(hashes);
             foreach (UInt256 hash in hashes)
             {
                 session.Tasks[hash] = DateTime.UtcNow;
             }
             foreach (InvPayload group in InvPayload.CreateGroup(InventoryType.Block, hashes.ToArray()))
             {
                 session.RemoteNode.Tell(Message.Create(MessageCommand.GetData, group));
             }
             return;
         }
     }
     if ((!HasHeaderTask || globalTasks[HeaderTaskHash] < MaxConncurrentTasks) && Blockchain.Singleton.HeaderHeight < session.StartHeight)
     {
         session.Tasks[HeaderTaskHash] = DateTime.UtcNow;
         IncrementGlobalTask(HeaderTaskHash);
         session.RemoteNode.Tell(Message.Create(MessageCommand.GetHeaders, GetBlocksPayload.Create(Blockchain.Singleton.CurrentHeaderHash)));
     }
     else if (Blockchain.Singleton.Height < session.StartHeight)
     {
         UInt256 hash = Blockchain.Singleton.CurrentBlockHash;
         for (uint i = Blockchain.Singleton.Height + 1; i <= Blockchain.Singleton.HeaderHeight; i++)
         {
             hash = Blockchain.Singleton.GetBlockHash(i);
             if (!globalTasks.ContainsKey(hash))
             {
                 hash = Blockchain.Singleton.GetBlockHash(i - 1);
                 break;
             }
         }
         session.RemoteNode.Tell(Message.Create(MessageCommand.GetBlocks, GetBlocksPayload.Create(hash)));
     }
 }
Пример #16
0
        public void ConstructorTest()
        {
            var invs = new Inventory[]
            {
                new Inventory(InventoryType.Block, new byte[32]),
                new Inventory(InventoryType.CompactBlock, Helper.GetBytes(32))
            };
            var pl = new InvPayload(invs);

            Assert.Equal(PayloadType.Inv, pl.PayloadType);
            Assert.Same(invs, pl.InventoryList);
        }
Пример #17
0
        /// <summary>
        /// Processes "inv" message received from the peer.
        /// </summary>
        /// <param name="invPayload">Payload of "inv" message to process.</param>
        private async Task ProcessInvAsync(InvPayload invPayload)
        {
            this.logger.LogTrace("({0}:'{1}')", nameof(invPayload), invPayload);

            if (invPayload.Inventory.Any(i => ((i.Type & InventoryType.MSG_BLOCK) != 0) && !this.chain.Contains(i.Hash)))
            {
                // No need of periodical refresh, the peer is notifying us.
                this.refreshTimer.Dispose();
                await this.TrySyncAsync().ConfigureAwait(false);
            }

            this.logger.LogTrace("(-)");
        }
Пример #18
0
        void ProcessInvPayload(InvPayload payload)
        {
            var unknownBlocks = new List <InvEntryPayload>();

            foreach (InvEntryPayload entry in payload.Entries)
            {
                if (entry.Type == InvEntryType.MSG_BLOCK)
                {
                    unknownBlocks.Add(entry);
                }
            }
            Connection.SendGetDataMessage(new InvPayload(unknownBlocks));
        }
Пример #19
0
 private void OnRelay(IInventory inventory)
 {
     if (!IsFullNode)
     {
         return;
     }
     //if (inventory.InventoryType == InventoryType.TX)
     //{
     //    if (bloom_filter != null && !bloom_filter.Test((Transaction)inventory))
     //        return;
     //}
     EnqueueMessage(MessageCommand.Inv, InvPayload.Create(inventory.InventoryType, inventory.Hash));
 }
Пример #20
0
        public void EnqueueMessage(string command, ISerializable payload = null)
        {
            TR.Enter();
            if (command == "inv")
            {
                InvPayload inv = (InvPayload)payload;
                TR.Log("message : {0} to {1} with {2}", command, RemoteEndpoint.Address, inv.Hashes[0].ToString());
            }
            else
            {
                TR.Log("message : {0} to {1}", command, RemoteEndpoint.Address);
            }
            bool is_single = false;

            switch (command)
            {
            case "addr":
            case "getaddr":
            case "getblocks":
            case "getheaders":
            case "mempool":
                is_single = true;
                break;
            }
            Queue <Message> message_queue;

            switch (command)
            {
            case "alert":
            case "consensus":
            case "filteradd":
            case "filterclear":
            case "filterload":
            case "getaddr":
            case "mempool":
                message_queue = message_queue_high;
                break;

            default:
                message_queue = message_queue_low;
                break;
            }
            lock (message_queue)
            {
                if (!is_single || message_queue.All(p => p.Command != command))
                {
                    message_queue.Enqueue(Message.Create(command, payload));
                }
            }
            TR.Exit();
        }
Пример #21
0
        private void OnGetTxnMessageReceived(Message msg)
        {
            InvPayload payload = msg.GetPayload <InvPayload>();

            if (payload.Type != InventoryType.TX)
            {
                throw new InvalidOperationException();
            }

            UInt256[] hashes = payload.Hashes.Where(p => sentHashes.Add(p)).ToArray();
            if (hashes.Length == 0)
            {
                return;
            }

            blockchain.Log($"OnGetTxn begin, count:{payload.Hashes.Length}, [{remoteNode.Remote.Address}]", Plugins.LogLevel.Debug);

            List <Transaction> transactions = new List <Transaction>();

            foreach (UInt256 hash in hashes)
            {
                Transaction tx = blockchain.GetTransaction(hash);
                if (tx != null)
                {
                    transactions.Add(tx);
                }
            }
            int count = transactions.Count;

            if (count > 0)
            {
                if (ProtocolSettings.Default.EnableCompressedRawTxn)
                {
                    foreach (CompressedTransactionPayload ctx_payload in CompressedTransactionPayload.CreateGroup(transactions.ToArray()))
                    {
                        Context.Parent.Tell(Message.Create(MessageType.CompressedTxn, ctx_payload));
                    }
                }
                else
                {
                    foreach (RawTransactionPayload rtx_payload in RawTransactionPayload.CreateGroup(transactions.ToArray()))
                    {
                        Context.Parent.Tell(Message.Create(MessageType.RawTxn, rtx_payload));
                    }
                }

                Context.Parent.Tell(RemoteNode.NewCounterMessage(RemoteNode.CounterType.Send, payload.Type, count));
            }

            blockchain.Log($"OnGetTxn end, count:{hashes.Length}=>{count}, [{remoteNode.Remote.Address}]", Plugins.LogLevel.Debug);
        }
        /// <summary>
        /// Sends transaction to peers.
        /// </summary>
        /// <param name="transaction">Transaction that will be propagated.</param>
        /// <param name="skipHalfOfThePeers">If set to <c>true</c> transaction will be send to all the peers we are connected to. Otherwise it will be sent to half of them.</param>
        protected void PropagateTransactionToPeers(Transaction transaction, bool skipHalfOfThePeers = false)
        {
            this.AddOrUpdate(transaction, State.ToBroadcast);

            var invPayload = new InvPayload(transaction);

            var peers            = this.connectionManager.ConnectedNodes.ToList();
            int propagateToCount = skipHalfOfThePeers ? (int)Math.Ceiling(peers.Count / 2.0) : peers.Count;

            for (int i = 0; i < propagateToCount; ++i)
            {
                peers[i].SendMessageAsync(invPayload).GetAwaiter().GetResult();
            }
        }
Пример #23
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);
                    }
                }
            }
        }
Пример #24
0
        private void OnInvMessageReceived(InvPayload payload)
        {
            TR.Enter();
            if (payload.Type != InventoryType.TX && payload.Type != InventoryType.Block && payload.Type != InventoryType.Consensus)
            {
                TR.Exit(); return;
            }
            HashSet <UInt256> hashes = new HashSet <UInt256>(payload.Hashes);

            lock (LocalNode.KnownHashes)
            {
                hashes.RemoveWhere(p => LocalNode.KnownHashes.TryGetValue(p, out DateTime time) && time + LocalNode.HashesExpiration >= DateTime.UtcNow);
            }
            if (hashes.Count == 0)
            {
                TR.Exit(); return;
            }
            lock (missions_global)
            {
                lock (missions)
                {
                    if (localNode.GlobalMissionsEnabled)
                    {
                        hashes.RemoveWhere(p => missions_global.TryGetValue(p, out DateTime time) && time + MissionExpiration >= DateTime.UtcNow);
                    }
                    if (hashes.Count > 0)
                    {
                        if (missions.Count == 0)
                        {
                            mission_start = DateTime.Now;
                        }
                        foreach (UInt256 hash in hashes)
                        {
                            if (!missions_global.ContainsKey(hash))
                            {
                                missions_global.Add(hash, DateTime.UtcNow);
                            }
                        }
                        missions.UnionWith(hashes);
                    }
                }
            }
            if (hashes.Count == 0)
            {
                TR.Exit(); return;
            }
            EnqueueMessage("getdata", InvPayload.Create(payload.Type, hashes.ToArray()));
            TR.Exit();
        }
Пример #25
0
 private void OnRelay(IInventory inventory)
 {
     if (Version?.Services.HasFlag(VersionServices.AcceptRelay) != true)
     {
         return;
     }
     if (inventory.InventoryType == InventoryType.TX)
     {
         if (bloom_filter != null && !bloom_filter.Test((Transaction)inventory))
         {
             return;
         }
     }
     EnqueueMessage(MessageCommand.Inv, InvPayload.Create(inventory.InventoryType, inventory.Hash));
 }
Пример #26
0
        public void TryDeserializeTest(Inventory[] items, byte[] data)
        {
            var  pl      = new InvPayload();
            var  stream  = new FastStreamReader(data);
            bool success = pl.TryDeserialize(stream, out string error);

            Assert.True(success, error);
            Assert.Null(error);
            Assert.Equal(items.Length, pl.InventoryList.Length);
            for (int i = 0; i < items.Length; i++)
            {
                Assert.Equal(items[i].InvType, pl.InventoryList[i].InvType);
                Assert.Equal(items[i].Hash, pl.InventoryList[i].Hash);
            }
        }
Пример #27
0
 private void OnRelay(IInventory inventory)
 {
     if (Version?.Relay != true)
     {
         return;
     }
     if (inventory.InventoryType == InventoryType.TX)
     {
         if (bloom_filter != null && !bloom_filter.Test((Transaction)inventory))
         {
             return;
         }
     }
     EnqueueMessage("inv", InvPayload.Create(inventory.InventoryType, inventory.Hash));
 }
        private async Task BroadcastTransactionToNetworkNodeAsync(SmartTransaction transaction, Node node)
        {
            Logger.LogInfo($"Trying to broadcast transaction with random node ({node.RemoteSocketAddress}):{transaction.GetHash()}.");
            if (!BitcoinStore.MempoolService.TryAddToBroadcastStore(transaction.Transaction, node.RemoteSocketEndpoint.ToString()))             // So we'll reply to INV with this transaction.
            {
                Logger.LogWarning($"Transaction {transaction.GetHash()} was already present in the broadcast store.");
            }
            var invPayload = new InvPayload(transaction.Transaction);

            // Give 7 seconds to send the inv payload.
            await node.SendMessageAsync(invPayload).WithAwaitCancellationAsync(TimeSpan.FromSeconds(7)).ConfigureAwait(false);             // ToDo: It's dangerous way to cancel. Implement proper cancellation to NBitcoin!

            if (BitcoinStore.MempoolService.TryGetFromBroadcastStore(transaction.GetHash(), out TransactionBroadcastEntry? entry))
            {
                // Give 7 seconds for serving.
                var timeout = 0;
                while (!entry.IsBroadcasted())
                {
                    if (timeout > 7)
                    {
                        throw new TimeoutException("Did not serve the transaction.");
                    }
                    await Task.Delay(1_000).ConfigureAwait(false);

                    timeout++;
                }
                node.DisconnectAsync("Thank you!");
                Logger.LogInfo($"Disconnected node: {node.RemoteSocketAddress}. Successfully broadcasted transaction: {transaction.GetHash()}.");

                // Give 21 seconds for propagation.
                timeout = 0;
                while (entry.GetPropagationConfirmations() < 2)
                {
                    if (timeout > 21)
                    {
                        throw new TimeoutException("Did not serve the transaction.");
                    }
                    await Task.Delay(1_000).ConfigureAwait(false);

                    timeout++;
                }
                Logger.LogInfo($"Transaction is successfully propagated: {transaction.GetHash()}.");
            }
            else
            {
                Logger.LogWarning($"Expected transaction {transaction.GetHash()} was not found in the broadcast store.");
            }
        }
Пример #29
0
        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);
            }
        }
Пример #30
0
        private void SendPrepareRequest()
        {
            Log($"send prepare request: height={context.BlockIndex} view={context.ViewNumber}");
            localNode.Tell(new LocalNode.SendDirectly {
                Inventory = context.MakePrepareRequest()
            });

            if (context.TransactionHashes.Length > 1)
            {
                foreach (InvPayload payload in InvPayload.CreateGroup(InventoryType.TX, context.TransactionHashes.Skip(1).ToArray()))
                {
                    localNode.Tell(Message.Create("inv", payload));
                }
            }
            ChangeTimer(TimeSpan.FromSeconds((Blockchain.SecondsPerBlock << (context.ViewNumber + 1)) - (context.ViewNumber == 0 ? Blockchain.SecondsPerBlock : 0)));
        }