예제 #1
0
        private async Task TestNodesConnectivityAndVersionAsync()
        {
            logger.LogInformation($"Checking nodes connectivity");

            var nodes = nodeRepository.GetNodes();

            if (!nodes.Any())
            {
                logger.LogWarning("There are no nodes present in database.");
            }

            foreach (var node in nodes)
            {
                var rpcClient = rpcClientFactory.Create(node.Host, node.Port, node.Username, node.Password);
                rpcClient.RequestTimeout = TimeSpan.FromSeconds(3);
                rpcClient.NumOfRetries   = 10;
                try
                {
                    var networkInfo = await rpcClient.GetNetworkInfoAsync();

                    if (!Nodes.IsNodeVersionValid(networkInfo.Version, out string error))
                    {
                        logger.LogError(error);
                    }
                    accessibleNodes.Add(node);
                    nodesAccessible = true;
                }
                catch (Exception)
                {
                    logger.LogWarning($"Node at address '{node.Host}:{node.Port}' is unreachable");
                }
            }
            logger.LogInformation($"Nodes connectivity check complete");
        }
        /// <summary>
        /// Call activezmqnotifications on nodes that haven't posted any events for a given period of time (ZmqConnectionTestIntervalSec config setting).
        /// </summary>
        private async Task PingNodesAsync(CancellationToken stoppingToken)
        {
            var nodesToPing = subscriptions
                              .Where(s => (clock.UtcNow() - s.Value.LastContactAt).TotalSeconds >= appSettings.ZmqConnectionTestIntervalSec)
                              .Select(s => s.Value.NodeId)
                              .Distinct()
                              .ToArray();

            if (nodesToPing.Any())
            {
                var nodes = nodeRepository.GetNodes().ToArray();
                foreach (long nodeId in nodesToPing)
                {
                    var node = nodes.FirstOrDefault(n => n.Id == nodeId);
                    if (node == null)
                    {
                        continue;
                    }

                    var bitcoind = bitcoindFactory.Create(node.Host, node.Port, node.Username, node.Password);
                    bitcoind.RequestTimeout = TimeSpan.FromSeconds(RPC_RESPONSE_TIMEOUT_SECONDS);
                    try
                    {
                        // Call activezmqnotifications rpc method just to check that node is still responding.
                        // No validation of the response is made here.
                        var notifications = await bitcoind.ActiveZmqNotificationsAsync(stoppingToken);

                        // If we got answer than update last message timestamp on all subscriptions of this node
                        if (notifications.Any())
                        {
                            foreach (var subscription in subscriptions.Where(s => s.Value.NodeId == node.Id).ToArray())
                            {
                                subscription.Value.LastPingAt = clock.UtcNow();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        // Call failed so put node on failed list
                        MarkAsFailed(node, ex.Message);
                        // Remove any active subscriptions because we need full reconnection to this node
                        UnsubscribeZmqNotifications(node);
                        logger.LogError(ex, $"Ping failed for node {node.Host}:{node.Port}. Will try to resubscribe.");
                    }
                }
            }
        }
예제 #3
0
        public async Task <Node> CreateNodeAsync(Node node)
        {
            logger.LogInformation($"Adding node {node}");
            // Try to connect to node
            var bitcoind = bitcoindFactory.Create(node.Host, node.Port, node.Username, node.Password);

            try
            {
                // try to call some method to test if connectivity parameters are correct
                _ = await bitcoind.GetBlockCountAsync();
            }
            catch (Exception ex)
            {
                throw new BadRequestException($"The node was not added. Unable to connect to node {node.Host}:{node.Port}.", ex);
            }

            RpcActiveZmqNotification[] notifications;
            try
            {
                notifications = await bitcoind.ActiveZmqNotificationsAsync();
            }
            catch (Exception ex)
            {
                throw new BadRequestException($"Node at address '{node.Host}:{node.Port}' did not return a valid response to call 'activeZmqNotifications'", ex);
            }


            if (!notifications.Any() || notifications.Select(x => x.Notification).Intersect(ZMQTopic.RequiredZmqTopics).Count() != ZMQTopic.RequiredZmqTopics.Length)
            {
                var missingNotifications = ZMQTopic.RequiredZmqTopics.Except(notifications.Select(x => x.Notification));
                throw new BadRequestException($"Node '{node.Host}:{node.Port}', does not have all required zmq notifications enabled. Missing notifications ({string.Join(",", missingNotifications)})");
            }

            var createdNode = nodeRepository.CreateNode(node);

            eventBus.Publish(new NodeAddedEvent()
            {
                CreationDate = clock.UtcNow(), CreatedNode = createdNode
            });

            return(createdNode);
        }
예제 #4
0
        IRpcClient[] GetRpcClients()
        {
            var result = nodes.GetNodes().Select(
                n => rpcClientFactory.Create(n.Host, n.Port, n.Username, n.Password)).ToArray();

            if (!result.Any())
            {
                throw new BadRequestException("No nodes available");
            }

            return(result);
        }
예제 #5
0
        private async Task ValidateNode(Node node, bool isUpdate = false)
        {
            // Try to connect to node
            var bitcoind = bitcoindFactory.Create(node.Host, node.Port, node.Username, node.Password);

            try
            {
                // try to call some method to test if connectivity parameters are correct
                var networkInfo = await bitcoind.GetNetworkInfoAsync();

                if (!Nodes.IsNodeVersionValid(networkInfo.Version, out string versionError))
                {
                    throw new BadRequestException(versionError);
                }
            }
            catch (Exception ex)
            {
                throw new BadRequestException($"The node was not { (isUpdate ? "updated" : "added") }. Unable to connect to node {node.Host}:{node.Port}.", ex);
            }

            RpcActiveZmqNotification[] notifications;
            try
            {
                notifications = await bitcoind.ActiveZmqNotificationsAsync();
            }
            catch (Exception ex)
            {
                throw new BadRequestException($"Node at address '{node.Host}:{node.Port}' did not return a valid response to call 'activeZmqNotifications'", ex);
            }

            if (!IsZMQNotificationsEndpointValid(node, notifications, out string error))
            {
                throw new BadRequestException(error);
            }

            if (!notifications.Any() || notifications.Select(x => x.Notification).Intersect(ZMQTopic.RequiredZmqTopics).Count() != ZMQTopic.RequiredZmqTopics.Length)
            {
                var missingNotifications = ZMQTopic.RequiredZmqTopics.Except(notifications.Select(x => x.Notification));
                throw new BadRequestException($"Node '{node.Host}:{node.Port}', does not have all required zmq notifications enabled. Missing notifications ({string.Join(",", missingNotifications)})");
            }
        }