Ejemplo n.º 1
0
        public void CanCreateBigSlimChain()
        {
            var main = new ConcurrentChain(LoadMainChain(), Network.Main);
            var c    = new SlimChain(main.GetBlock(0).HashBlock);

            foreach (var item in main.EnumerateToTip(main.GetBlock(0).HashBlock))
            {
                c.TrySetTip(item.HashBlock, item.Previous?.HashBlock);
            }
            Assert.Equal(main.Height, c.Height);
            Assert.Equal(main.Tip.HashBlock, c.Tip);
            // Can up the capacity without errors
            c.SetCapacity(main.Height + 3000);
            Assert.Equal(main.Height, c.Height);
            Assert.Equal(main.Tip.HashBlock, c.Tip);
            Assert.Equal(main.GetBlock(main.Tip.HashBlock).HashBlock, c.GetBlock(c.Tip).Hash);
        }
Ejemplo n.º 2
0
        private async Task ConnectToBitcoinD(CancellationToken cancellation, GetBlockchainInfoResponse blockchainInfo)
        {
            var node = GetHandshakedNode();

            if (node != null)
            {
                return;
            }
            try
            {
                EnsureNodeDisposed();
                _Chain.ResetToGenesis();
                _Chain.SetCapacity((int)(blockchainInfo.Headers * 1.1));
                if (_Configuration.CacheChain)
                {
                    LoadChainFromCache();
                    if (!await HasBlock(_OriginalRPC, _Chain.Tip))
                    {
                        Logs.Configuration.LogInformation($"{_Network.CryptoCode}: The cached chain contains a tip unknown to the node, dropping the cache...");
                        _Chain.ResetToGenesis();
                    }
                }
                var heightBefore = _Chain.Height;
                using (var timeout = CancellationTokenSource.CreateLinkedTokenSource(cancellation))
                {
                    timeout.CancelAfter(_Network.ChainLoadingTimeout);
                    Logs.Configuration.LogInformation($"{_Network.CryptoCode}: Trying to connect via the P2P protocol to trusted node ({_ChainConfiguration.NodeEndpoint.ToEndpointString()})...");
                    var  userAgent   = "NBXplorer-" + RandomUtils.GetInt64();
                    bool handshaked  = false;
                    bool connected   = false;
                    bool chainLoaded = false;
                    using (var handshakeTimeout = CancellationTokenSource.CreateLinkedTokenSource(cancellation))
                    {
                        try
                        {
                            handshakeTimeout.CancelAfter(TimeSpan.FromSeconds(10));
                            node = await Node.ConnectAsync(_Network.NBitcoinNetwork, _ChainConfiguration.NodeEndpoint, new NodeConnectionParameters()
                            {
                                UserAgent           = userAgent,
                                ConnectCancellation = handshakeTimeout.Token,
                                IsRelay             = true
                            });

                            connected = true;
                            Logs.Explorer.LogInformation($"{Network.CryptoCode}: TCP Connection succeed, handshaking...");
                            node.VersionHandshake(handshakeTimeout.Token);
                            handshaked = true;
                            Logs.Explorer.LogInformation($"{Network.CryptoCode}: Handshaked");
                            var loadChainTimeout = _Network.NBitcoinNetwork.ChainName == ChainName.Regtest ? TimeSpan.FromSeconds(5) : _Network.ChainCacheLoadingTimeout;
                            if (_Chain.Height < 5)
                            {
                                loadChainTimeout = TimeSpan.FromDays(7);                                 // unlimited
                            }
                            Logs.Configuration.LogInformation($"{_Network.CryptoCode}: Loading chain from node");
                            try
                            {
                                using (var cts1 = CancellationTokenSource.CreateLinkedTokenSource(cancellation))
                                {
                                    cts1.CancelAfter(loadChainTimeout);
                                    Logs.Explorer.LogInformation($"{Network.CryptoCode}: Loading chain...");
                                    node.SynchronizeSlimChain(_Chain, cancellationToken: cts1.Token);
                                }
                            }
                            catch when(!cancellation.IsCancellationRequested)                              // Timeout happens with SynchronizeChain, if so, throw away the cached chain
                            {
                                Logs.Explorer.LogInformation($"{Network.CryptoCode}: Failed to load chain before timeout, let's try again without the chain cache...");
                                _Chain.ResetToGenesis();
                                node.SynchronizeSlimChain(_Chain, cancellationToken: cancellation);
                            }
                            Logs.Explorer.LogInformation($"{Network.CryptoCode}: Chain loaded");
                            chainLoaded = true;
                            var peer = (await _OriginalRPC.GetPeersInfoAsync())
                                       .FirstOrDefault(p => p.SubVersion == userAgent);
                            if (IsWhitelisted(peer))
                            {
                                Logs.Explorer.LogInformation($"{Network.CryptoCode}: NBXplorer is correctly whitelisted by the node");
                            }
                            else
                            {
                                var addressStr = peer.Address is IPEndPoint end?end.Address.ToString() : peer.Address?.ToString();

                                Logs.Explorer.LogWarning($"{Network.CryptoCode}: Your NBXplorer server is not whitelisted by your node," +
                                                         $" you should add \"whitelist={addressStr}\" to the configuration file of your node. (Or use whitebind)");
                            }
                        }
                        catch
                        {
                            if (!connected)
                            {
                                Logs.Explorer.LogWarning($"{Network.CryptoCode}: NBXplorer failed to connect to the node via P2P ({_ChainConfiguration.NodeEndpoint.ToEndpointString()}).{Environment.NewLine}" +
                                                         $"It may come from: A firewall blocking the traffic, incorrect IP or port, or your node may not have an available connection slot. {Environment.NewLine}" +
                                                         $"To make sure your node have an available connection slot, use \"whitebind\" or \"whitelist\" in your node configuration. (typically whitelist=127.0.0.1 if NBXplorer and the node are on the same machine.){Environment.NewLine}");
                            }
                            else if (!handshaked)
                            {
                                Logs.Explorer.LogWarning($"{Network.CryptoCode}: NBXplorer connected to the remote node but failed to handhsake via P2P.{Environment.NewLine}" +
                                                         $"Your node may not have an available connection slot, or you may try to connect to the wrong node. (ie, trying to connect to a LTC node on the BTC configuration).{Environment.NewLine}" +
                                                         $"To make sure your node have an available connection slot, use \"whitebind\" or \"whitelist\" in your node configuration. (typically whitelist=127.0.0.1 if NBXplorer and the node are on the same machine.){Environment.NewLine}");
                            }
                            else if (!chainLoaded)
                            {
                                Logs.Explorer.LogWarning($"{Network.CryptoCode}: NBXplorer connected and handshaked the remote node but failed to load the chain of header.{Environment.NewLine}" +
                                                         $"Your connection may be throttled, or you may try to connect to the wrong node. (ie, trying to connect to a LTC node on the BTC configuration).{Environment.NewLine}");
                            }
                            throw;
                        }
                    }
                }
                Logs.Configuration.LogInformation($"{_Network.CryptoCode}: Height: " + _Chain.Height);
                if (_Configuration.CacheChain && heightBefore != _Chain.Height)
                {
                    SaveChainInCache();
                }
                GC.Collect();
                node.Behaviors.Add(new SlimChainBehavior(_Chain));
                var explorer = (ExplorerBehavior)_ExplorerPrototype.Clone();
                node.Behaviors.Add(explorer);
                node.StateChanged += Node_StateChanged;
                _Node              = node;
            }
            catch
            {
                EnsureNodeDisposed(node ?? _Node);
                throw;
            }
        }