internal void RequestGetBlocks() { RemoteNode[] nodes = GetRemoteNodes(); GetBlocksPayload payload = GetBlocksPayload.Create(Blockchain.Default.CurrentBlockHash); foreach (RemoteNode node in nodes) { node.EnqueueMessage("getblocks", payload); } }
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); }
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))); } }
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); } }
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>()); }
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); }
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))); } }
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); } } } }
private void OnBroadcastGetHeadersCommand(UInt256 hash) { OnBroadcastCommand(MessageCommand.GetHeaders, GetBlocksPayload.Create(hash)); }
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))); } }
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; } } }
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; } } }
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))); } } }
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(); }
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; } } }
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; } } }