private void OnTimer(Timer timer) { if (timer.Height != context.BlockIndex || timer.ViewNumber != context.ViewNumber) { return; } Log($"timeout: height={timer.Height} view={timer.ViewNumber} state={context.State}"); if (context.State.HasFlag(ConsensusState.Primary) && !context.State.HasFlag(ConsensusState.RequestSent)) { Log($"send prepare request: height={timer.Height} view={timer.ViewNumber}"); context.State |= ConsensusState.RequestSent; if (!context.State.HasFlag(ConsensusState.SignatureSent)) { FillContext(); context.Timestamp = Math.Max(DateTime.UtcNow.ToTimestamp(), context.Snapshot.GetHeader(context.PrevHash).Timestamp + 1); context.Signatures[context.MyIndex] = context.MakeHeader().Sign(context.KeyPair); } SignAndRelay(context.MakePrepareRequest()); if (context.TransactionHashes.Length > 1) { foreach (InvPayload payload in InvPayload.CreateGroup(InventoryType.TX, context.TransactionHashes.Skip(1).ToArray())) { system.LocalNode.Tell(Message.Create("inv", payload)); } } ChangeTimer(TimeSpan.FromSeconds(Blockchain.SecondsPerBlock << (timer.ViewNumber + 1))); } else if ((context.State.HasFlag(ConsensusState.Primary) && context.State.HasFlag(ConsensusState.RequestSent)) || context.State.HasFlag(ConsensusState.Backup)) { RequestChangeView(); } }
private void OnNewTasks(InvPayload payload) { if (!sessions.TryGetValue(Sender, out TaskSession session)) { return; } if (payload.Type == InventoryType.TX && blockchain.Height < blockchain.HeaderHeight) { RequestTasks(session); return; } HashSet <UInt256> hashes = new HashSet <UInt256>(payload.Hashes); hashes.ExceptWith(knownHashes); if (payload.Type == InventoryType.Block) { session.AvailableTasks.UnionWith(hashes.Where(p => globalTasks.Contains(p))); } hashes.ExceptWith(globalTasks); if (hashes.Count == 0) { RequestTasks(session); return; } globalTasks.UnionWith(hashes); foreach (UInt256 hash in hashes) { session.Tasks[hash] = DateTime.UtcNow; } foreach (InvPayload group in InvPayload.CreateGroup(payload.Type, hashes.ToArray())) { Sender.Tell(Message.Create("getdata", group)); } }
private void OnMemPoolMessageReceived() { foreach (InvPayload payload in InvPayload.CreateGroup(InventoryType.TX, Blockchain.Singleton.MemPool.GetVerifiedTransactions().Select(p => p.Hash).ToArray())) { Context.Parent.Tell(Message.Create("inv", payload)); } }
private void OnNewTasks(InvPayload payload) { if (!sessions.TryGetValue(Sender, out TaskSession session)) { return; } // Do not accept payload of type InventoryType.TX if not synced on best known HeaderHeight if (payload.Type == InventoryType.TX && Blockchain.Singleton.Height < sessions.Values.Max(p => p.LastBlockIndex)) { return; } HashSet <UInt256> hashes = new HashSet <UInt256>(payload.Hashes); // Remove all previously processed knownHashes from the list that is being requested hashes.Remove(knownHashes); // Remove those that are already in process by other sessions hashes.Remove(globalTasks); if (hashes.Count == 0) { return; } // Update globalTasks with the ones that will be requested within this current session foreach (UInt256 hash in hashes) { IncrementGlobalTask(hash); session.InvTasks[hash] = TimeProvider.Current.UtcNow; } foreach (InvPayload group in InvPayload.CreateGroup(payload.Type, hashes.ToArray())) { Sender.Tell(Message.Create(MessageCommand.GetData, group)); } }
private void RequestInventoryData(InventoryType type, UInt256[] hashes, IActorRef sender) { if (hashes.Length == 0) { return; } if (hashes.Length == 1) { sender.Tell(Message.Create(MessageType.GetData, InvPayload.Create(type, hashes[0]))); } else { string cmd; if (type == InventoryType.Block) { cmd = MessageType.GetBlk; } else if (type == InventoryType.TX) { cmd = MessageType.GetTxn; } else { return; } foreach (InvPayload group in InvPayload.CreateGroup(type, hashes)) { sender.Tell(Message.Create(cmd, group)); } } Sender.Tell(RemoteNode.NewCounterMessage(RemoteNode.CounterType.Request, type, hashes.Length)); }
private void OnMemPoolMessageReceived(Message msg) { foreach (InvPayload payload in InvPayload.CreateGroup(InventoryType.TX, blockchain.GetMemoryPool().Select(p => p.Hash).ToArray())) { Context.Parent.Tell(Message.Create(MessageType.Inv, payload)); } }
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 RequestTasks(TaskSession session) { 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))); } else if (Blockchain.Singleton.HeaderHeight >= session.LastBlockIndex && TimeProvider.Current.UtcNow.ToTimestamp() - PingCoolingOffPeriod >= Blockchain.Singleton.GetBlock(Blockchain.Singleton.CurrentHeaderHash)?.Timestamp) { session.RemoteNode.Tell(Message.Create("ping", PingPayload.Create(Blockchain.Singleton.Height))); } }
private void OnRestartTasks(InvPayload payload) { knownHashes.ExceptWith(payload.Hashes); globalTasks.ExceptWith(payload.Hashes); foreach (InvPayload group in InvPayload.CreateGroup(payload.Type, payload.Hashes)) { system.LocalNode.Tell(Message.Create("getdata", group)); } }
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 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))); }
// 广播并清空缓存队列中的交易数据 private void BroadcastRawTransactions() { if (rawtxnList.Count == 0) { return; } // 控制每组消息里的交易数量,向远程节点发送交易的清单 foreach (InvPayload payload in InvPayload.CreateGroup(InventoryType.TX, rawtxnList.Select(p => p.Hash).ToArray())) { system.LocalNode.Tell(Message.Create(MessageType.Inv, payload)); } // 清空队列 rawtxnList.Clear(); }
private void OnNewTasks(InvPayload payload) { if (!sessions.TryGetValue(Sender, out TaskSession session)) { return; } // Do not accept payload of type InventoryType.TX if not synced on HeaderHeight uint currentHeight = NativeContract.Ledger.CurrentIndex(system.StoreView); uint headerHeight = system.HeaderCache.Last?.Index ?? currentHeight; if (currentHeight < headerHeight && (payload.Type == InventoryType.TX || (payload.Type == InventoryType.Block && currentHeight < session.LastBlockIndex - InvPayload.MaxHashesCount))) { RequestTasks(Sender, session); return; } HashSet <UInt256> hashes = new HashSet <UInt256>(payload.Hashes); // Remove all previously processed knownHashes from the list that is being requested hashes.Remove(knownHashes); // Add to AvailableTasks the ones, of type InventoryType.Block, that are global (already under process by other sessions) if (payload.Type == InventoryType.Block) { session.AvailableTasks.UnionWith(hashes.Where(p => globalInvTasks.ContainsKey(p))); } // Remove those that are already in process by other sessions hashes.Remove(globalInvTasks); if (hashes.Count == 0) { RequestTasks(Sender, session); return; } // Update globalTasks with the ones that will be requested within this current session foreach (UInt256 hash in hashes) { IncrementGlobalTask(hash); session.InvTasks[hash] = TimeProvider.Current.UtcNow; } foreach (InvPayload group in InvPayload.CreateGroup(payload.Type, hashes.ToArray())) { Sender.Tell(Message.Create(MessageCommand.GetData, group)); } }
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))); } }
private void OnTimer(Timer timer) { if (context.State.HasFlag(ConsensusState.BlockSent)) { return; } if (timer.Height != context.BlockIndex || timer.ViewNumber != context.ViewNumber) { return; } Log($"timeout: height={timer.Height} view={timer.ViewNumber} state={context.State}", LogLevel.Debug); if (context.State.HasFlag(ConsensusState.Primary) && !context.State.HasFlag(ConsensusState.RequestSent)) { // 没有新的交易请求,并且没有到最长出块时间 if (!blockchain.HasVerifiedTransaction() && TimeProvider.Current.UtcNow - block_received_time < MaxTimeSpanPerBlock) { // 等待下一次出块时间再判断是否需要出块 ChangeTimer(Blockchain.TimePerBlock); return; } context.State |= ConsensusState.RequestSent; if (!context.State.HasFlag(ConsensusState.SignatureSent)) { context.Fill(); context.SignHeader(); } Log($"send prepare request: height={timer.Height} view={timer.ViewNumber} tx={context.TransactionHashes.Length}"); 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(MessageType.Inv, payload)); } } SetNextTimer(timer.ViewNumber + 1); } else if ((context.State.HasFlag(ConsensusState.Primary) && context.State.HasFlag(ConsensusState.RequestSent)) || context.State.HasFlag(ConsensusState.Backup)) { RequestChangeView(); } }
public void CreateGroup() { var hashes = new UInt256[InvPayload.MaxHashesCount + 1]; for (int x = 0; x < hashes.Length; x++) { byte[] data = new byte[32]; Array.Copy(BitConverter.GetBytes(x), data, 4); hashes[x] = new UInt256(data); } var array = InvPayload.CreateGroup(InventoryType.TX, hashes).ToArray(); Assert.AreEqual(2, array.Length); Assert.AreEqual(InventoryType.TX, array[0].Type); Assert.AreEqual(InventoryType.TX, array[1].Type); CollectionAssert.AreEqual(hashes.Take(InvPayload.MaxHashesCount).ToArray(), array[0].Hashes); CollectionAssert.AreEqual(hashes.Skip(InvPayload.MaxHashesCount).ToArray(), array[1].Hashes); }
private void OnNewTasks(InvPayload payload) { if (!sessions.TryGetValue(Sender, out TaskSession session)) { return; } // Do not accept payload of type InventoryType.TX if not synced on best known HeaderHeight if (payload.Type == InventoryType.TX && Blockchain.Singleton.Height < Blockchain.Singleton.HeaderHeight) { RequestTasks(session); return; } HashSet <UInt256> hashes = new HashSet <UInt256>(payload.Hashes); // Remove all previously processed knownHashes from the list that is being requested hashes.Remove(knownHashes); // Add to AvailableTasks the ones, of type InventoryType.Block, that are global (already under process by other sessions) if (payload.Type == InventoryType.Block) { session.AvailableTasks.UnionWith(hashes.Where(p => globalTasks.ContainsKey(p))); } // Remove those that are already in process by other sessions hashes.Remove(globalTasks); if (hashes.Count == 0) { RequestTasks(session); return; } // Update globalTasks with the ones that will be requested within this current session foreach (UInt256 hash in hashes) { IncrementGlobalTask(hash); session.Tasks[hash] = DateTime.UtcNow; } foreach (InvPayload group in InvPayload.CreateGroup(payload.Type, hashes.ToArray())) { Sender.Tell(Message.Create(MessageCommand.GetData, group)); } }
private void SendPrepareRequest() { Log($"Sending {nameof(PrepareRequest)}: height={context.Block.Index} view={context.ViewNumber}"); localNode.Tell(new LocalNode.SendDirectly { Inventory = context.MakePrepareRequest() }); if (context.Validators.Length == 1) { CheckPreparations(); } if (context.TransactionHashes.Length > 0) { foreach (InvPayload payload in InvPayload.CreateGroup(InventoryType.TX, context.TransactionHashes)) { localNode.Tell(Message.Create(MessageCommand.Inv, payload)); } } ChangeTimer(TimeSpan.FromMilliseconds((neoSystem.Settings.MillisecondsPerBlock << (context.ViewNumber + 1)) - (context.ViewNumber == 0 ? neoSystem.Settings.MillisecondsPerBlock : 0))); }
private void OnTimer(Timer timer) { if (context.State.HasFlag(ConsensusState.BlockSent)) { return; } if (timer.Height != context.BlockIndex || timer.ViewNumber != context.ViewNumber) { return; } Log($"timeout: height={timer.Height} view={timer.ViewNumber} state={context.State}"); if (context.State.HasFlag(ConsensusState.Primary) && !context.State.HasFlag(ConsensusState.RequestSent)) { Log($"send prepare request: height={timer.Height} view={timer.ViewNumber}"); context.State |= ConsensusState.RequestSent; if (!context.State.HasFlag(ConsensusState.SignatureSent)) { context.Fill(); context.SignHeader(); } 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 << (timer.ViewNumber + 1))); } else if ((context.State.HasFlag(ConsensusState.Primary) && context.State.HasFlag(ConsensusState.RequestSent)) || context.State.HasFlag(ConsensusState.Backup)) { RequestChangeView(); } }
private void OnNewTasks(InvPayload payload) { if (!sessions.TryGetValue(Sender, out TaskSession session)) { return; } if (payload.Type == InventoryType.TX && Blockchain.Singleton.Height < Blockchain.Singleton.HeaderHeight) { RequestTasks(session); return; } HashSet <UInt256> hashes = new HashSet <UInt256>(payload.Hashes); hashes.Remove(knownHashes); if (payload.Type == InventoryType.Block) { session.AvailableTasks.UnionWith(hashes.Where(p => globalTasks.ContainsKey(p))); } hashes.Remove(globalTasks); if (hashes.Count == 0) { RequestTasks(session); return; } foreach (UInt256 hash in hashes) { IncrementGlobalTask(hash); session.Tasks[hash] = DateTime.UtcNow; } foreach (InvPayload group in InvPayload.CreateGroup(payload.Type, hashes.ToArray())) { Sender.Tell(Message.Create(MessageCommand.GetData, group)); } }
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))); } }
private void RequestTasks(IActorRef remoteNode, TaskSession session) { if (session.HasTooManyTasks) { return; } DataCache snapshot = system.StoreView; // 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 = system.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 && !system.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 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))); } } }