public void ProcessFindNodeMessage(FindNodeMessage discoveryMessage) { NodeStats.AddNodeStatsEvent(NodeStatsEventType.DiscoveryFindNodeIn); RefreshNodeContactTime(); Node[] nodes = _nodeTable.GetClosestNodes(discoveryMessage.SearchedNodeId); SendNeighbors(nodes); }
public void OnPongMessageTest() { //receiving pong _discoveryManager.OnIncomingMessage(new PongMessage { FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port), FarPublicKey = _publicKey }); //expecting to activate node as valid peer var nodes = _nodeTable.GetClosestNodes(); Assert.AreEqual(1, nodes.Length); var node = nodes.First(); Assert.AreEqual(_host, node.Host); Assert.AreEqual(_port, node.Port); var manager = _discoveryManager.GetNodeLifecycleManager(node); Assert.AreEqual(NodeLifecycleState.Active, manager.State); }
public void ProcessFindNodeMsg(FindNodeMsg msg) { if (!IsBonded) { return; } NodeStats.AddNodeStatsEvent(NodeStatsEventType.DiscoveryFindNodeIn); RefreshNodeContactTime(); Node[] nodes = _nodeTable.GetClosestNodes(msg.SearchedNodeId).ToArray(); SendNeighbors(nodes); }
public void EvictCandidateStateWonEvictionTest() { //adding 3 active nodes var managers = new List <INodeLifecycleManager>(); for (var i = 0; i < 3; i++) { var host = "192.168.1." + i; var node = new Node(_nodeIds[i], host, _port); var manager = _discoveryManager.GetNodeLifecycleManager(node); managers.Add(manager); Assert.AreEqual(NodeLifecycleState.New, manager.State); _discoveryManager.OnIncomingMessage(new PongMessage { FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port), FarPublicKey = _nodeIds[i] }); Assert.AreEqual(NodeLifecycleState.Active, manager.State); } //table should contain 3 active nodes var closestNodes = _nodeTable.GetClosestNodes(); Assert.IsTrue(closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 1); Assert.IsTrue(closestNodes.Count(x => x.Host == managers[1].ManagedNode.Host) == 1); Assert.IsTrue(closestNodes.Count(x => x.Host == managers[2].ManagedNode.Host) == 1); //adding 4th node - table can store only 3, eviction process should start var candidateNode = new Node(_nodeIds[3], _host, _port); var candidateManager = _discoveryManager.GetNodeLifecycleManager(candidateNode); Assert.AreEqual(NodeLifecycleState.New, candidateManager.State); _discoveryManager.OnIncomingMessage(new PongMessage { FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port), FarPublicKey = _nodeIds[3] }); Assert.AreEqual(NodeLifecycleState.Active, candidateManager.State); var evictionCandidate = managers.First(x => x.State == NodeLifecycleState.EvictCandidate); //receiving pong for eviction candidate - should survive _discoveryManager.OnIncomingMessage(new PongMessage { FarAddress = new IPEndPoint(IPAddress.Parse(evictionCandidate.ManagedNode.Host), _port), FarPublicKey = evictionCandidate.ManagedNode.Id }); //Thread.Sleep(100); //3th node should survive, 4th node should be active but not in the table Assert.That(() => candidateManager.State, Is.EqualTo(NodeLifecycleState.ActiveExcluded).After(100, 50)); Assert.That(() => evictionCandidate.State, Is.EqualTo(NodeLifecycleState.Active).After(100, 50)); //Assert.AreEqual(NodeLifecycleState.ActiveExcluded, candidateManager.State); //Assert.AreEqual(NodeLifecycleState.Active, evictionCandidate.State); closestNodes = _nodeTable.GetClosestNodes(); Assert.That(() => closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 1, Is.True.After(100, 50)); Assert.That(() => closestNodes.Count(x => x.Host == managers[1].ManagedNode.Host) == 1, Is.True.After(100, 50)); Assert.That(() => closestNodes.Count(x => x.Host == managers[2].ManagedNode.Host) == 1, Is.True.After(100, 50)); Assert.That(() => closestNodes.Count(x => x.Host == candidateNode.Host) == 0, Is.True.After(100, 50)); //Assert.IsTrue(closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 1); //Assert.IsTrue(closestNodes.Count(x => x.Host == managers[1].ManagedNode.Host) == 1); //Assert.IsTrue(closestNodes.Count(x => x.Host == managers[2].ManagedNode.Host) == 1); //Assert.IsTrue(closestNodes.Count(x => x.Host == candidateNode.Host) == 0); }
public async Task LocateNodesAsync(byte[]?searchedNodeId, CancellationToken cancellationToken) { if (_masterNode == null) { throw new InvalidOperationException("Master node has not been initialized"); } ISet <Keccak> alreadyTriedNodes = new HashSet <Keccak>(); if (_logger.IsDebug) { _logger.Debug($"Starting discovery process for node: {(searchedNodeId != null ? $"randomNode: {new PublicKey(searchedNodeId).ToShortString()}" : $"masterNode: {_masterNode.Id}")}"); } int nodesCountBeforeDiscovery = NodesCountBeforeDiscovery; Node[] tryCandidates = new Node[_discoveryConfig.BucketSize]; // max bucket size here for (int i = 0; i < _discoveryConfig.MaxDiscoveryRounds; i++) { Array.Clear(tryCandidates, 0, tryCandidates.Length); int candidatesCount; int attemptsCount = 0; while (true) { //if searched node is not specified master node is used IEnumerable <Node> closestNodes = searchedNodeId != null?_nodeTable.GetClosestNodes(searchedNodeId) : _nodeTable.GetClosestNodes(); candidatesCount = 0; foreach (Node closestNode in closestNodes.Where(node => !alreadyTriedNodes.Contains(node.IdHash))) { tryCandidates[candidatesCount++] = closestNode; if (candidatesCount > tryCandidates.Length - 1) { break; } } if (attemptsCount++ > 20 || candidatesCount > 0) { break; } if (_logger.IsTrace) { _logger.Trace($"Waiting {_discoveryConfig.DiscoveryNewCycleWaitTime} for new nodes"); } //we need to wait some time for pong messages received from new nodes we reached out to try { await Task.Delay(_discoveryConfig.DiscoveryNewCycleWaitTime, cancellationToken); } catch (OperationCanceledException) { return; } } if (candidatesCount == 0) { if (_logger.IsTrace) { _logger.Trace("No more closer candidates"); } break; } int successRequestsCount = 0; int failRequestCount = 0; int nodesTriedCount = 0; while (true) { int count = failRequestCount > 0 ? failRequestCount : _discoveryConfig.Concurrency; IEnumerable <Node> nodesToSend = tryCandidates.Skip(nodesTriedCount).Take(count); IEnumerable <Task <Result> > sendFindNodeTasks = SendFindNodes(searchedNodeId, nodesToSend, alreadyTriedNodes); Result?[] results = await Task.WhenAll(sendFindNodeTasks); if (results.Length == 0) { if (_logger.IsDebug) { _logger.Debug($"No more nodes to send, sent {successRequestsCount} successful requests, failedRequestCounter: {failRequestCount}, nodesTriedCounter: {nodesTriedCount}"); } break; } nodesTriedCount += results.Length; foreach (Result?result in results) { if ((result?.ResultType ?? ResultType.Failure) == ResultType.Failure) { failRequestCount++; } else { successRequestsCount++; } } if (successRequestsCount >= _discoveryConfig.Concurrency) { if (_logger.IsTrace) { _logger.Trace($"Sent {successRequestsCount} successful requests, failedRequestCounter: {failRequestCount}, nodesTriedCounter: {nodesTriedCount}"); } break; } } } int nodesCountAfterDiscovery = _nodeTable.Buckets.Sum(x => x.BondedItemsCount); if (_logger.IsDebug) { _logger.Debug($"Finished discovery cycle, tried contacting {alreadyTriedNodes.Count} nodes. All nodes count before the process: {nodesCountBeforeDiscovery}, after the process: {nodesCountAfterDiscovery}"); } if (_logger.IsTrace) { LogNodeTable(); } }
public async Task LocateNodesAsync(byte[] searchedNodeId, CancellationToken cancellationToken) { List <Keccak> alreadyTriedNodes = new List <Keccak>(); if (_logger.IsDebug) { _logger.Debug($"Starting discovery process for node: {(searchedNodeId != null ? $"randomNode: {new PublicKey(searchedNodeId).ToShortString()}" : $"masterNode: {_masterNode.Id}")}"); } int nodesCountBeforeDiscovery = _nodeTable.Buckets.Sum(x => x.BondedItems.Count); for (int i = 0; i < _discoveryConfig.MaxDiscoveryRounds; i++) { Node[] tryCandidates; int candTryIndex = 0; while (true) { //if searched node is not specified master node is used Node[] closestNodes = searchedNodeId != null?_nodeTable.GetClosestNodes(searchedNodeId) : _nodeTable.GetClosestNodes(); tryCandidates = closestNodes.Where(node => !alreadyTriedNodes.Contains(node.IdHash)).ToArray(); if (tryCandidates.Any()) { break; } if (candTryIndex > 20) { break; } candTryIndex = candTryIndex + 1; if (_logger.IsTrace) { _logger.Trace($"Waiting {_discoveryConfig.DiscoveryNewCycleWaitTime} for new nodes"); } //we need to wait some time for pong messages received from new nodes we reached out to try { await Task.Delay(_discoveryConfig.DiscoveryNewCycleWaitTime, cancellationToken); } catch (OperationCanceledException) { return; } } if (!tryCandidates.Any()) { if (_logger.IsTrace) { _logger.Trace("No more closer candidates"); } break; } int successRequestsCount = 0; int failRequestCount = 0; int nodesTriedCount = 0; while (true) { int count = failRequestCount > 0 ? failRequestCount : _discoveryConfig.Concurrency; Node[] nodesToSend = tryCandidates.Skip(nodesTriedCount).Take(count).ToArray(); if (!nodesToSend.Any()) { if (_logger.IsDebug) { _logger.Debug($"No more nodes to send, sent {successRequestsCount} successfull requests, failedRequestCounter: {failRequestCount}, nodesTriedCounter: {nodesTriedCount}"); } break; } nodesTriedCount += nodesToSend.Length; alreadyTriedNodes.AddRange(nodesToSend.Select(x => x.IdHash)); Result[] results = await SendFindNode(nodesToSend, searchedNodeId, cancellationToken); foreach (Result result in results) { if ((result?.ResultType ?? ResultType.Failure) == ResultType.Failure) { failRequestCount++; } else { successRequestsCount++; } } if (successRequestsCount >= _discoveryConfig.Concurrency) { if (_logger.IsTrace) { _logger.Trace($"Sent {successRequestsCount} successfull requests, failedRequestCounter: {failRequestCount}, nodesTriedCounter: {nodesTriedCount}"); } break; } } } int nodesCountAfterDiscovery = _nodeTable.Buckets.Sum(x => x.BondedItems.Count); if (_logger.IsDebug) { _logger.Debug($"Finished discovery cycle, tried contacting {alreadyTriedNodes.Count} nodes. All nodes count before the process: {nodesCountBeforeDiscovery}, after the process: {nodesCountAfterDiscovery}"); } if (_logger.IsTrace) { LogNodeTable(); } }
public void EvictCandidateStateWonEvictionTest() { //adding 3 active nodes List <INodeLifecycleManager> managers = new(); for (int i = 0; i < 3; i++) { string host = "192.168.1." + i; Node node = new(_nodeIds[i], host, _port); INodeLifecycleManager?manager = _discoveryManager.GetNodeLifecycleManager(node); if (manager is null) { throw new Exception("Manager is null"); } managers.Add(manager); Assert.AreEqual(NodeLifecycleState.New, manager.State); PongMsg msgI = new (_nodeIds[i], GetExpirationTime(), new byte[32]); msgI.FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port); _discoveryManager.OnIncomingMsg(msgI); Assert.AreEqual(NodeLifecycleState.New, manager.State); } //table should contain 3 active nodes IEnumerable <Node> closestNodes = _nodeTable.GetClosestNodes().ToArray(); Assert.IsTrue(closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 0); Assert.IsTrue(closestNodes.Count(x => x.Host == managers[1].ManagedNode.Host) == 0); Assert.IsTrue(closestNodes.Count(x => x.Host == managers[2].ManagedNode.Host) == 0); //adding 4th node - table can store only 3, eviction process should start Node candidateNode = new(_nodeIds[3], _host, _port); INodeLifecycleManager?candidateManager = _discoveryManager.GetNodeLifecycleManager(candidateNode); Assert.AreEqual(NodeLifecycleState.New, candidateManager?.State); PongMsg pongMsg = new (_nodeIds[3], GetExpirationTime(), new byte[32]); pongMsg.FarAddress = new IPEndPoint(IPAddress.Parse(_host), _port); _discoveryManager.OnIncomingMsg(pongMsg); Assert.AreEqual(NodeLifecycleState.New, candidateManager?.State); INodeLifecycleManager evictionCandidate = managers.First(x => x.State == NodeLifecycleState.EvictCandidate); //receiving pong for eviction candidate - should survive PongMsg msg = new (evictionCandidate.ManagedNode.Id, GetExpirationTime(), new byte[32]); msg.FarAddress = new IPEndPoint(IPAddress.Parse(evictionCandidate.ManagedNode.Host), _port); _discoveryManager.OnIncomingMsg(msg); //await Task.Delay(100); //3th node should survive, 4th node should be active but not in the table Assert.That(() => candidateManager?.State, Is.EqualTo(NodeLifecycleState.ActiveExcluded).After(100, 50)); Assert.That(() => evictionCandidate.State, Is.EqualTo(NodeLifecycleState.Active).After(100, 50)); //Assert.AreEqual(NodeLifecycleState.ActiveExcluded, candidateManager.State); //Assert.AreEqual(NodeLifecycleState.Active, evictionCandidate.State); closestNodes = _nodeTable.GetClosestNodes(); Assert.That(() => closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 1, Is.True.After(100, 50)); Assert.That(() => closestNodes.Count(x => x.Host == managers[1].ManagedNode.Host) == 1, Is.True.After(100, 50)); Assert.That(() => closestNodes.Count(x => x.Host == managers[2].ManagedNode.Host) == 1, Is.True.After(100, 50)); Assert.That(() => closestNodes.Count(x => x.Host == candidateNode.Host) == 0, Is.True.After(100, 50)); //Assert.IsTrue(closestNodes.Count(x => x.Host == managers[0].ManagedNode.Host) == 1); //Assert.IsTrue(closestNodes.Count(x => x.Host == managers[1].ManagedNode.Host) == 1); //Assert.IsTrue(closestNodes.Count(x => x.Host == managers[2].ManagedNode.Host) == 1); //Assert.IsTrue(closestNodes.Count(x => x.Host == candidateNode.Host) == 0); }
public async Task LocateNodesAsync(byte[] searchedNodeId) { var alreadyTriedNodes = new List <string>(); _logger.Info($"Starting location process for node: {(searchedNodeId != null ? new Hex(searchedNodeId).ToString() : "masterNode: " + _masterNode.Id)}"); for (var i = 0; i < _configurationProvider.MaxDiscoveryRounds; i++) { Node[] tryCandidates; var candTryIndex = 0; while (true) { //if searched node is not specified master node is used var closestNodes = searchedNodeId != null?_nodeTable.GetClosestNodes(searchedNodeId) : _nodeTable.GetClosestNodes(); tryCandidates = closestNodes.Where(node => !alreadyTriedNodes.Contains(node.IdHashText)).ToArray(); if (tryCandidates.Any()) { break; } if (candTryIndex > 20) { break; } candTryIndex = candTryIndex + 1; _logger.Debug($"Waiting {_configurationProvider.DiscoveryNewCycleWaitTime} for new nodes"); //we need to wait some time for pong messages received from new nodes we reached out to await Task.Delay(_configurationProvider.DiscoveryNewCycleWaitTime); //Thread.Sleep(_configurationProvider.DiscoveryNewCycleWaitTime); } if (!tryCandidates.Any()) { _logger.Debug("No more closer candidates"); break; } var successRequestsCount = 0; var failRequestCount = 0; var nodesTriedCount = 0; while (true) { var count = failRequestCount > 0 ? failRequestCount : _configurationProvider.Concurrency; var nodesToSend = tryCandidates.Skip(nodesTriedCount).Take(count).ToArray(); if (!nodesToSend.Any()) { _logger.Info($"No more nodes to send, sent {successRequestsCount} successfull requests, failedRequestCounter: {failRequestCount}, nodesTriedCounter: {nodesTriedCount}"); break; } nodesTriedCount += nodesToSend.Length; alreadyTriedNodes.AddRange(nodesToSend.Select(x => x.IdHashText)); var results = await SendFindNode(nodesToSend, searchedNodeId); foreach (var result in results) { if (result.ResultType == ResultType.Failure) { failRequestCount++; } else { successRequestsCount++; } } if (successRequestsCount >= _configurationProvider.Concurrency) { _logger.Info($"Sent {successRequestsCount} successfull requests, failedRequestCounter: {failRequestCount}, nodesTriedCounter: {nodesTriedCount}"); break; } } } _logger.Info($"Finished locating nodes, triedNodesCount: {alreadyTriedNodes.Count}"); LogNodeTable(); }