private void RequestTasks(IActorRef remoteNode, TaskSession session) { if (session.HasTooManyTasks) { return; } DataCache snapshot = Blockchain.Singleton.View; // 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 => NativeContract.Ledger.ContainsBlock(snapshot, 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.InvTasks[hash] = DateTime.UtcNow; } foreach (InvPayload group in InvPayload.CreateGroup(InventoryType.Block, hashes.ToArray())) { remoteNode.Tell(Message.Create(MessageCommand.GetData, group)); } return; } } uint currentHeight = NativeContract.Ledger.CurrentIndex(snapshot); uint headerHeight = Blockchain.Singleton.HeaderCache.Last?.Index ?? currentHeight; // 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 || globalInvTasks[HeaderTaskHash] < MaxConncurrentTasks) && headerHeight < session.LastBlockIndex && !Blockchain.Singleton.HeaderCache.Full) { session.InvTasks[HeaderTaskHash] = DateTime.UtcNow; IncrementGlobalTask(HeaderTaskHash); remoteNode.Tell(Message.Create(MessageCommand.GetHeaders, GetBlockByIndexPayload.Create(headerHeight))); } else if (currentHeight < session.LastBlockIndex) { uint startHeight = currentHeight; while (globalIndexTasks.ContainsKey(++startHeight)) { } if (startHeight > session.LastBlockIndex || startHeight >= currentHeight + InvPayload.MaxHashesCount) { return; } uint endHeight = startHeight; while (!globalIndexTasks.ContainsKey(++endHeight) && endHeight <= session.LastBlockIndex && endHeight <= currentHeight + InvPayload.MaxHashesCount) { } uint count = Math.Min(endHeight - startHeight, InvPayload.MaxHashesCount); for (uint i = 0; i < count; i++) { session.IndexTasks[startHeight + i] = TimeProvider.Current.UtcNow; IncrementGlobalTask(startHeight + i); } remoteNode.Tell(Message.Create(MessageCommand.GetBlockByIndex, GetBlockByIndexPayload.Create(startHeight, (short)count))); } else if (!session.MempoolSent) { session.MempoolSent = true; remoteNode.Tell(Message.Create(MessageCommand.Mempool)); } }
private void BroadcastMessage(MessageCommand command, ISerializable payload = null) { BroadcastMessage(Message.Create(command, payload)); }
private void EnqueueMessage(MessageCommand command, ISerializable payload = null) { EnqueueMessage(Message.Create(command, payload)); }
private void OnPingMessageReceived(PingPayload payload) { Context.Parent.Tell(payload); Context.Parent.Tell(Message.Create(MessageCommand.Pong, PingPayload.Create(Blockchain.Singleton.Height, payload.Nonce))); }
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))); } } }