예제 #1
0
        public void ProcessFindNodeMessage(FindNodeMessage discoveryMessage)
        {
            NodeStats.AddNodeStatsEvent(NodeStatsEventType.DiscoveryFindNodeIn);
            RefreshNodeContactTime();

            Node[] nodes = _nodeTable.GetClosestNodes(discoveryMessage.SearchedNodeId);
            SendNeighbors(nodes);
        }
예제 #2
0
        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);
        }
예제 #3
0
    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);
        }
예제 #5
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();
        }
    }
예제 #6
0
        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();
            }
        }
예제 #7
0
        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);
        }
예제 #8
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();
        }