예제 #1
0
        internal void RequestGetBlocks()
        {
            RemoteNode[] nodes = GetRemoteNodes();

            GetBlocksPayload payload = GetBlocksPayload.Create(Blockchain.Default.CurrentBlockHash);

            foreach (RemoteNode node in nodes)
            {
                node.EnqueueMessage("getblocks", payload);
            }
        }
예제 #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.Singleton.GetBlock(UInt256.Parse(args[2]));
                }
                else
                {
                    payload = Blockchain.Singleton.Store.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 = Blockchain.Singleton.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);
            }
            system.LocalNode.Tell(Message.Create(command, payload));
            Console.WriteLine($"command:{command}");
            return(true);
        }
예제 #3
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)));
     }
 }
예제 #4
0
파일: RemoteNode.cs 프로젝트: ys8090/NEU
 private void OnHeadersMessageReceived(HeadersPayload payload)
 {
     if (Blockchain.Default == null)
     {
         return;
     }
     Blockchain.Default.AddHeaders(payload.Headers);
     if (Blockchain.Default.HeaderHeight < Version.StartHeight)
     {
         EnqueueMessage("getheaders", GetBlocksPayload.Create(Blockchain.Default.CurrentHeaderHash), true);
     }
 }
예제 #5
0
 private async Task OnHeadersMessageReceivedAsync(HeadersPayload payload)
 {
     if (Blockchain.Default == null)
     {
         return;
     }
     Blockchain.Default.AddHeaders(payload.Headers);
     if (Blockchain.Default.HeaderHeight < Version.StartHeight)
     {
         await SendMessageAsync("getheaders", GetBlocksPayload.Create(Blockchain.Default.GetLeafHeaderHashes()));
     }
 }
        public void DeserializeAndSerialize()
        {
            var test  = GetBlocksPayload.Create(UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"), 5);
            var clone = test.ToArray().AsSerializable <GetBlocksPayload>();

            Assert.AreEqual(test.Count, clone.Count);
            Assert.AreEqual(test.HashStart, clone.HashStart);
            Assert.AreEqual(5, clone.Count);
            Assert.AreEqual("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01", clone.HashStart.ToString());

            Assert.ThrowsException <FormatException>(() => GetBlocksPayload.Create(UInt256.Zero, -2).ToArray().AsSerializable <GetBlocksPayload>());
            Assert.ThrowsException <FormatException>(() => GetBlocksPayload.Create(UInt256.Zero, 0).ToArray().AsSerializable <GetBlocksPayload>());
        }
예제 #7
0
        private bool OnBroadcastCommand(string[] args)
        {
            if (!Enum.TryParse(args[1], true, out MessageCommand command))
            {
                Console.WriteLine($"Command \"{args[1]}\" is not supported.");
                return(true);
            }
            ISerializable payload = null;

            switch (command)
            {
            case MessageCommand.Addr:
                payload = AddrPayload.Create(NetworkAddressWithTime.Create(IPAddress.Parse(args[2]), DateTime.UtcNow.ToTimestamp(), new FullNodeCapability(), new ServerCapability(NodeCapabilityType.TcpServer, ushort.Parse(args[3]))));
                break;

            case MessageCommand.Block:
                if (args[2].Length == 64 || args[2].Length == 66)
                {
                    payload = Blockchain.Singleton.GetBlock(UInt256.Parse(args[2]));
                }
                else
                {
                    payload = Blockchain.Singleton.Store.GetBlock(uint.Parse(args[2]));
                }
                break;

            case MessageCommand.GetBlocks:
            case MessageCommand.GetHeaders:
                payload = GetBlocksPayload.Create(UInt256.Parse(args[2]));
                break;

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

            case MessageCommand.Transaction:
                payload = Blockchain.Singleton.GetTransaction(UInt256.Parse(args[2]));
                break;

            default:
                Console.WriteLine($"Command \"{command}\" is not supported.");
                return(true);
            }
            system.LocalNode.Tell(Message.Create(command, payload));
            return(true);
        }
예제 #8
0
파일: TaskManager.cs 프로젝트: ProDog/Zoro
 private void RequestTasks(TaskSession session)
 {
     if (session.HasTask)
     {
         return;
     }
     if (session.AvailableTasks.Count > 0)
     {
         session.AvailableTasks.ExceptWith(knownHashes);
         session.AvailableTasks.RemoveWhere(p => blockchain.ContainsBlock(p));
         HashSet <UInt256> hashes = new HashSet <UInt256>(session.AvailableTasks);
         hashes.ExceptWith(globalTasks);
         if (hashes.Count > 0)
         {
             session.AvailableTasks.ExceptWith(hashes);
             globalTasks.UnionWith(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("getdata", group));
             }
             return;
         }
     }
     if (!HeaderTask && blockchain.HeaderHeight < session.Version.StartHeight)
     {
         session.Tasks[UInt256.Zero] = DateTime.UtcNow;
         session.RemoteNode.Tell(Message.Create("getheaders", GetBlocksPayload.Create(blockchain.CurrentHeaderHash)));
     }
     else if (blockchain.Height < session.Version.StartHeight)
     {
         UInt256 hash = blockchain.CurrentBlockHash;
         for (uint i = blockchain.Height + 1; i <= blockchain.HeaderHeight; i++)
         {
             hash = blockchain.GetBlockHash(i);
             if (!globalTasks.Contains(hash))
             {
                 hash = blockchain.GetBlockHash(i - 1);
                 break;
             }
         }
         session.RemoteNode.Tell(Message.Create("getblocks", GetBlocksPayload.Create(hash)));
     }
 }
예제 #9
0
파일: RemoteNode.cs 프로젝트: ys8090/NEU
 public virtual void Disconnect(bool error)
 {
     if (Interlocked.Exchange(ref disposed, 1) == 0)
     {
         Disconnected?.Invoke(this, error);
         bool needSync = false;
         lock (missions_global)
             lock (missions)
                 if (missions.Count > 0)
                 {
                     missions_global.ExceptWith(missions);
                     needSync = true;
                 }
         if (needSync)
         {
             lock (localNode.connectedPeers)
                 foreach (RemoteNode node in localNode.connectedPeers)
                 {
                     node.EnqueueMessage("getblocks", GetBlocksPayload.Create(Blockchain.Default.CurrentBlockHash), true);
                 }
         }
     }
 }
예제 #10
0
 private void OnBroadcastGetHeadersCommand(UInt256 hash)
 {
     OnBroadcastCommand(MessageCommand.GetHeaders, GetBlocksPayload.Create(hash));
 }
예제 #11
0
        private void RequestTasks(TaskSession session)
        {
            if (session.HasTask)
            {
                return;
            }
            // If there are pending tasks of InventoryType.Block we should process them
            if (session.AvailableTasks.Count > 0)
            {
                session.AvailableTasks.Remove(knownHashes);
                // Search any similar hash that is on Singleton's knowledge, which means, on the way or already processed
                session.AvailableTasks.RemoveWhere(p => Blockchain.Singleton.ContainsBlock(p));
                HashSet <UInt256> hashes = new HashSet <UInt256>(session.AvailableTasks);
                hashes.Remove(MemPoolTaskHash);
                if (hashes.Count > 0)
                {
                    foreach (UInt256 hash in hashes.ToArray())
                    {
                        if (!IncrementGlobalTask(hash))
                        {
                            hashes.Remove(hash);
                        }
                    }
                    session.AvailableTasks.Remove(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;
                }
            }

            // When the number of AvailableTasks is no more than 0, no pending tasks of InventoryType.Block, it should process pending the tasks of headers
            // If not HeaderTask pending to be processed it should ask for more Blocks
            if ((!HasHeaderTask || globalTasks[HeaderTaskHash] < MaxConncurrentTasks) && Blockchain.Singleton.HeaderHeight < session.LastBlockIndex)
            {
                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.LastBlockIndex)
            {
                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)));
            }
            else if (Blockchain.Singleton.HeaderHeight >= session.LastBlockIndex &&
                     TimeProvider.Current.UtcNow.ToTimestampMS() - PingCoolingOffPeriod >= Blockchain.Singleton.GetBlock(Blockchain.Singleton.CurrentHeaderHash)?.Timestamp)
            {
                if (session.AvailableTasks.Remove(MemPoolTaskHash))
                {
                    session.RemoteNode.Tell(Message.Create(MessageCommand.Mempool));
                }

                session.RemoteNode.Tell(Message.Create(MessageCommand.Ping, PingPayload.Create(Blockchain.Singleton.Height)));
            }
        }
예제 #12
0
파일: RemoteNode.cs 프로젝트: ys8090/NEU
        internal async void StartProtocol()
        {
            if (!await SendMessageAsync(Message.Create("version", VersionPayload.Create(localNode.Port, localNode.Nonce, localNode.UserAgent))))
            {
                return;
            }
            Message message = await ReceiveMessageAsync(HalfMinute);

            if (message == null)
            {
                return;
            }
            if (message.Command != "version")
            {
                Disconnect(true);
                return;
            }
            try
            {
                Version = message.Payload.AsSerializable <VersionPayload>();
            }
            catch (EndOfStreamException)
            {
                Disconnect(false);
                return;
            }
            catch (FormatException)
            {
                Disconnect(true);
                return;
            }
            if (Version.Nonce == localNode.Nonce)
            {
                Disconnect(true);
                return;
            }
            bool isSelf;

            lock (localNode.connectedPeers)
            {
                isSelf = localNode.connectedPeers.Where(p => p != this).Any(p => p.RemoteEndpoint.Address.Equals(RemoteEndpoint.Address) && p.Version?.Nonce == Version.Nonce);
            }
            if (isSelf)
            {
                Disconnect(false);
                return;
            }
            if (ListenerEndpoint != null)
            {
                if (ListenerEndpoint.Port != Version.Port)
                {
                    Disconnect(true);
                    return;
                }
            }
            else if (Version.Port > 0)
            {
                ListenerEndpoint = new IPEndPoint(RemoteEndpoint.Address, Version.Port);
            }
            if (!await SendMessageAsync(Message.Create("verack")))
            {
                return;
            }
            message = await ReceiveMessageAsync(HalfMinute);

            if (message == null)
            {
                return;
            }
            if (message.Command != "verack")
            {
                Disconnect(true);
                return;
            }
            if (Blockchain.Default?.HeaderHeight < Version.StartHeight)
            {
                EnqueueMessage("getheaders", GetBlocksPayload.Create(Blockchain.Default.CurrentHeaderHash), true);
            }
            StartSendLoop();
            while (disposed == 0)
            {
                if (Blockchain.Default != null)
                {
                    if (missions.Count == 0 && Blockchain.Default.Height < Version.StartHeight)
                    {
                        EnqueueMessage("getblocks", GetBlocksPayload.Create(Blockchain.Default.CurrentBlockHash), true);
                    }
                }
                TimeSpan timeout = missions.Count == 0 ? HalfHour : OneMinute;
                message = await ReceiveMessageAsync(timeout);

                if (message == null)
                {
                    break;
                }
                if (DateTime.Now - mission_start > OneMinute &&
                    message.Command != "block" && message.Command != "consensus" && message.Command != "tx")
                {
                    Disconnect(false);
                    break;
                }
                try
                {
                    OnMessageReceived(message);
                }
                catch (EndOfStreamException)
                {
                    Disconnect(false);
                    break;
                }
                catch (FormatException)
                {
                    Disconnect(true);
                    break;
                }
            }
        }
예제 #13
0
        private void RunProtocol()
        {
            if (!SendMessage(Message.Create("version", VersionPayload.Create(localNode.Port, localNode.Nonce, localNode.UserAgent))))
            {
                return;
            }
            Message message = ReceiveMessage(TimeSpan.FromSeconds(30));

            if (message == null)
            {
                return;
            }
            if (message.Command != "version")
            {
                Disconnect(true);
                return;
            }
            try
            {
                Version = message.Payload.AsSerializable <VersionPayload>();
            }
            catch (EndOfStreamException)
            {
                Disconnect(false);
                return;
            }
            catch (FormatException)
            {
                Disconnect(true);
                return;
            }
            if (Version.Nonce == localNode.Nonce)
            {
                Disconnect(true);
                return;
            }
            lock (localNode.pendingPeers)
            {
                lock (localNode.connectedPeers)
                {
                    if (localNode.connectedPeers.Any(p => p.RemoteEndpoint.Address.Equals(RemoteEndpoint.Address) && p.Version.Nonce == Version.Nonce))
                    {
                        Disconnect(false);
                        return;
                    }
                    localNode.connectedPeers.Add(this);
                }
                if (ListenerEndpoint != null)
                {
                    localNode.pendingPeers.Remove(ListenerEndpoint);
                }
            }
            if (ListenerEndpoint != null)
            {
                if (ListenerEndpoint.Port != Version.Port)
                {
                    Disconnect(true);
                    return;
                }
            }
            else if (Version.Port > 0)
            {
                ListenerEndpoint = new IPEndPoint(RemoteEndpoint.Address, Version.Port);
            }
            if (!SendMessage(Message.Create("verack")))
            {
                return;
            }
            message = ReceiveMessage(TimeSpan.FromSeconds(30));
            if (message == null)
            {
                return;
            }
            if (message.Command != "verack")
            {
                Disconnect(true);
                return;
            }
            if (Blockchain.Default?.HeaderHeight < Version.StartHeight)
            {
                HashSet <UInt256> hashes = new HashSet <UInt256>(Blockchain.Default.GetLeafHeaderHashes());
                hashes.UnionWith(hashes.Select(p => Blockchain.Default.GetHeader(p).PrevBlock).ToArray());
                EnqueueMessage("getheaders", GetBlocksPayload.Create(hashes), true);
            }
            sendThread.Start();
            while (disposed == 0)
            {
                if (Blockchain.Default != null && !Blockchain.Default.IsReadOnly)
                {
                    if (missions.Count == 0 && Blockchain.Default.Height < Version.StartHeight)
                    {
                        EnqueueMessage("getblocks", GetBlocksPayload.Create(new[] { Blockchain.Default.CurrentBlockHash }), true);
                    }
                }
                TimeSpan timeout = missions.Count == 0 ? TimeSpan.FromMinutes(30) : TimeSpan.FromSeconds(60);
                message = ReceiveMessage(timeout);
                if (message == null)
                {
                    break;
                }
                try
                {
                    OnMessageReceived(message);
                }
                catch (EndOfStreamException)
                {
                    Disconnect(false);
                    break;
                }
                catch (FormatException)
                {
                    Disconnect(true);
                    break;
                }
            }
        }
예제 #14
0
 private void RequestTasks(TaskSession session)
 {
     if (!_expiredTimes.TryGetValue(session.RemoteNode.Path, out var expireTime) || expireTime < DateTime.UtcNow)
     {
         session.RemoteNode.Tell(Message.Create("ping", PingPayload.Create(Blockchain.Singleton.Height)));
         _expiredTimes[session.RemoteNode.Path] = DateTime.UtcNow.AddSeconds(PingCoolingOffPeriod);
     }
     if (session.HasTask)
     {
         return;
     }
     if (session.AvailableTasks.Count > 0)
     {
         session.AvailableTasks.Remove(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.Remove(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("getdata", group));
             }
             return;
         }
     }
     if ((!HasHeaderTask || globalTasks[HeaderTaskHash] < MaxConncurrentTasks) && Blockchain.Singleton.HeaderHeight < session.LastBlockIndex)
     {
         session.Tasks[HeaderTaskHash] = DateTime.UtcNow;
         IncrementGlobalTask(HeaderTaskHash);
         session.RemoteNode.Tell(Message.Create("getheaders", GetBlocksPayload.Create(Blockchain.Singleton.CurrentHeaderHash)));
     }
     else if (Blockchain.Singleton.Height < session.LastBlockIndex)
     {
         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("getblocks", GetBlocksPayload.Create(hash)));
     }
     if (!HasStateRootTask)
     {
         if (Blockchain.Singleton.ExpectStateRootIndex < Blockchain.Singleton.Height)
         {
             var state_root_state = Blockchain.Singleton.GetStateRoot(Blockchain.Singleton.ExpectStateRootIndex);
             if (state_root_state is null || state_root_state.Flag == StateRootVerifyFlag.Invalid)
             {
                 return;
             }
             var start_index = Blockchain.Singleton.ExpectStateRootIndex;
             var count       = Math.Min(Blockchain.Singleton.Height - start_index, StateRootsPayload.MaxStateRootsCount);
             StateRootSyncTime = DateTime.UtcNow;
             IncrementGlobalTask(StateRootTaskHash);
             system.LocalNode.Tell(Message.Create("getroots", GetStateRootsPayload.Create(start_index, count)));
         }
     }
 }
예제 #15
0
        internal async void StartProtocol()
        {
#if !NET47
            //There is a bug in .NET Core 2.0 that blocks async method which returns void.
            await Task.Yield();
#endif
            TR.Enter();

            bool          messageSent = false;
            IndentContext ic          = TR.SaveContextAndShuffle();
            try
            {
                TR.Log("message : {0} to {1}", "version", RemoteEndpoint.Address);
                messageSent = await SendMessageAsync(Message.Create("version", VersionPayload.Create(localNode.Port, localNode.Nonce, localNode.UserAgent)));
            }
            finally
            {
                TR.RestoreContext(ic);
            }
            if (!messageSent)
            {
                TR.Exit();
                return;
            }
            Message message = null;
            ic = TR.SaveContextAndShuffle();
            try
            {
                message = await ReceiveMessageAsync(HalfMinute);
            }
            finally
            {
                TR.RestoreContext(ic);
            }
            if (message == null)
            {
                return;
            }
            TR.Log("message : {0} from {1}", message.Command, RemoteEndpoint.Address);
            if (message.Command != "version")
            {
                TR.Log();
                Disconnect(true);
                TR.Exit();
                return;
            }
            try
            {
                Version = message.Payload.AsSerializable <VersionPayload>();
            }
            catch (EndOfStreamException)
            {
                TR.Log();
                Disconnect(false);
                TR.Exit();
                return;
            }
            catch (FormatException)
            {
                TR.Log();
                Disconnect(true);
                TR.Exit();
                return;
            }
            if (Version.Nonce == localNode.Nonce)
            {
                TR.Log();
                Disconnect(true);
                TR.Exit();
                return;
            }
            bool isSelf;
            lock (localNode.connectedPeers)
            {
                isSelf = localNode.connectedPeers.Where(p => p != this).Any(p => p.RemoteEndpoint.Address.Equals(RemoteEndpoint.Address) && p.Version?.Nonce == Version.Nonce);
            }
            if (isSelf)
            {
                TR.Log();
                Disconnect(false);
                TR.Exit();
                return;
            }
            if (ListenerEndpoint == null && Version.Port > 0)
            {
                ListenerEndpoint = new IPEndPoint(RemoteEndpoint.Address, Version.Port);
            }

            ic = TR.SaveContextAndShuffle();
            try
            {
                messageSent = await SendMessageAsync(Message.Create("verack"));

                TR.Log("message : {0} to {1}", "verack", RemoteEndpoint.Address);
            }
            finally
            {
                TR.RestoreContext(ic);
            }
            if (!messageSent)
            {
                TR.Exit();
                return;
            }
            ic = TR.SaveContextAndShuffle();
            try
            {
                message = await ReceiveMessageAsync(HalfMinute);
            }
            finally
            {
                TR.RestoreContext(ic);
            }

            if (message == null)
            {
                TR.Exit();
                return;
            }
            TR.Log("message : {0} from {1}", message.Command, RemoteEndpoint.Address);
            if (message.Command != "verack")
            {
                TR.Log();
                Disconnect(true);
                TR.Exit();
                return;
            }
            if (Blockchain.Default?.HeaderHeight < Version.StartHeight)
            {
                TR.Log("local header height : {0}, remote height : {1}, {2}", Blockchain.Default?.HeaderHeight, Version.StartHeight, RemoteEndpoint.Address);
                EnqueueMessage("getheaders", GetBlocksPayload.Create(Blockchain.Default.CurrentHeaderHash));
                TR.Log("current header hash : {0}", Blockchain.Default.CurrentHeaderHash.ToString());
            }
            StartSendLoop();
            while (disposed == 0)
            {
                if (Blockchain.Default != null)
                {
                    if (missions.Count == 0 && Blockchain.Default.Height < Version.StartHeight)
                    {
                        TR.Log("local height : {0}, remote height : {1}, {2}", Blockchain.Default.Height, Version.StartHeight, RemoteEndpoint.Address);
                        EnqueueMessage("getblocks", GetBlocksPayload.Create(Blockchain.Default.CurrentBlockHash));
                    }
                }
                TimeSpan timeout = missions.Count == 0 ? HalfHour : OneMinute;
                ic = TR.SaveContextAndShuffle();
                try
                {
                    message = await ReceiveMessageAsync(timeout);
                }
                finally
                {
                    TR.RestoreContext(ic);
                }
                if (message == null)
                {
                    break;
                }
                if (DateTime.Now - mission_start > OneMinute &&
                    message.Command != "block" && message.Command != "consensus" && message.Command != "tx")
                {
                    TR.Log();
                    Disconnect(false);
                    break;
                }
                try
                {
                    OnMessageReceived(message);
                }
                catch (EndOfStreamException)
                {
                    TR.Log();
                    Disconnect(false);
                    break;
                }
                catch (FormatException)
                {
                    TR.Log();
                    Disconnect(true);
                    break;
                }
            }
            TR.Exit();
        }
예제 #16
0
        internal async void StartProtocol()
        {
            if (!await SendMessageAsync("version", VersionPayload.Create(localNode.LocalEndpoint.Port, localNode.UserAgent, Blockchain.Default.Height)))
            {
                return;
            }
            Message message = await ReceiveMessageAsync(TimeSpan.FromSeconds(30));

            if (message == null)
            {
                return;
            }
            if (message.Command != "version")
            {
                Disconnect(true);
                return;
            }
            try
            {
                Version = message.Payload.AsSerializable <VersionPayload>();
            }
            catch (FormatException)
            {
                Disconnect(true);
                return;
            }
            if (RemoteEndpoint == null)
            {
                IPAddress  ip             = ((IPEndPoint)tcp.Client.RemoteEndPoint).Address.MapToIPv6();
                IPEndPoint remoteEndpoint = new IPEndPoint(ip, Version.Port);
                lock (localNode.pendingPeers)
                {
                    lock (localNode.connectedPeers)
                    {
                        if (localNode.pendingPeers.All(p => p.RemoteEndpoint != remoteEndpoint) && !localNode.connectedPeers.ContainsKey(remoteEndpoint))
                        {
                            RemoteEndpoint = remoteEndpoint;
                        }
                    }
                }
                if (RemoteEndpoint == null)
                {
                    Disconnect(false);
                    return;
                }
            }
            if (!await SendMessageAsync("verack"))
            {
                return;
            }
            message = await ReceiveMessageAsync(TimeSpan.FromSeconds(30));

            if (message == null)
            {
                return;
            }
            if (message.Command != "verack")
            {
                Disconnect(true);
                return;
            }
            lock (localNode.pendingPeers)
            {
                lock (localNode.connectedPeers)
                {
                    localNode.connectedPeers.Add(RemoteEndpoint, this);
                }
                localNode.pendingPeers.Remove(this);
            }
            if (Blockchain.Default.HeaderHeight < Version.StartHeight)
            {
                HashSet <UInt256> hashes = new HashSet <UInt256>(Blockchain.Default.GetLeafHeaderHashes());
                hashes.UnionWith(hashes.Select(p => Blockchain.Default.GetHeader(p).PrevBlock).ToArray());
                await SendMessageAsync("getheaders", GetBlocksPayload.Create(hashes));
            }
            while (disposed == 0)
            {
                if (Blockchain.Default != null && !Blockchain.Default.IsReadOnly)
                {
                    if (missions.Count == 0 && Blockchain.Default.Height < Blockchain.Default.HeaderHeight)
                    {
                        if (!await SendMessageAsync("getblocks", GetBlocksPayload.Create(new[] { Blockchain.Default.CurrentBlockHash })))
                        {
                            break;
                        }
                    }
                }
                TimeSpan timeout = missions.Count == 0 ? TimeSpan.FromMinutes(30) : TimeSpan.FromSeconds(60);
                message = await ReceiveMessageAsync(timeout);

                if (message == null)
                {
                    break;
                }
                try
                {
                    await OnMessageReceivedAsync(message);
                }
                catch (FormatException)
                {
                    Disconnect(true);
                    break;
                }
            }
        }
예제 #17
0
        private void RunProtocol()
        {
            if (!SendMessage(Message.Create("version", VersionPayload.Create(localNode.Port, localNode.Nonce, localNode.UserAgent))))
            {
                return;
            }
            Message message = ReceiveMessage(TimeSpan.FromSeconds(30));

            if (message == null)
            {
                return;
            }
            if (message.Command != "version")
            {
                Disconnect(true);
                return;
            }
            try
            {
                Version = message.Payload.AsSerializable <VersionPayload>();
            }
            catch (EndOfStreamException)
            {
                Disconnect(false);
                return;
            }
            catch (FormatException)
            {
                Disconnect(true);
                return;
            }
            if (Version.Nonce == localNode.Nonce)
            {
                Disconnect(true);
                return;
            }
            lock (localNode.connectedPeers)
            {
                if (localNode.connectedPeers.Where(p => p != this).Any(p => p.RemoteEndpoint.Address.Equals(RemoteEndpoint.Address) && p.Version?.Nonce == Version.Nonce))
                {
                    Disconnect(false);
                    return;
                }
            }
            if (ListenerEndpoint != null)
            {
                if (ListenerEndpoint.Port != Version.Port)
                {
                    Disconnect(true);
                    return;
                }
            }
            else if (Version.Port > 0)
            {
                ListenerEndpoint = new IPEndPoint(RemoteEndpoint.Address, Version.Port);
            }
            if (!SendMessage(Message.Create("verack")))
            {
                return;
            }
            message = ReceiveMessage(TimeSpan.FromSeconds(30));
            if (message == null)
            {
                return;
            }
            if (message.Command != "verack")
            {
                Disconnect(true);
                return;
            }
            if (Blockchain.Default?.HeaderHeight < Version.StartHeight)
            {
                EnqueueMessage("getheaders", GetBlocksPayload.Create(Blockchain.Default.CurrentHeaderHash), true);
            }
            sendThread.Name = $"RemoteNode.SendLoop@{RemoteEndpoint}";
            sendThread.Start();
            while (disposed == 0)
            {
                if (Blockchain.Default?.IsReadOnly == false)
                {
                    if (missions.Count == 0 && Blockchain.Default.Height < Version.StartHeight)
                    {
                        EnqueueMessage("getblocks", GetBlocksPayload.Create(Blockchain.Default.CurrentBlockHash), true);
                    }
                }
                TimeSpan timeout = missions.Count == 0 ? TimeSpan.FromMinutes(30) : TimeSpan.FromSeconds(60);
                message = ReceiveMessage(timeout);
                if (message == null)
                {
                    break;
                }
                try
                {
                    OnMessageReceived(message);
                }
                catch (EndOfStreamException)
                {
                    Disconnect(false);
                    break;
                }
                catch (FormatException)
                {
                    Disconnect(true);
                    break;
                }
            }
        }