示例#1
0
        private static async Task AddKnownBitcoinFullNodeAsHiddenServiceAsync(AddressManager addressManager)
        {
            if (Network == Network.RegTest)
            {
                return;
            }

            //  curl -s https://bitnodes.21.co/api/v1/snapshots/latest/ | egrep -o '[a-z0-9]{16}\.onion:?[0-9]*' | sort -ru
            // Then filtered to include only /Satoshi:0.17.x
            var fullBaseDirectory = Path.GetFullPath(AppContext.BaseDirectory);

            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                if (!fullBaseDirectory.StartsWith('/'))
                {
                    fullBaseDirectory.Insert(0, "/");
                }
            }

            var onions = await File.ReadAllLinesAsync(Path.Combine(fullBaseDirectory, "OnionSeeds", $"{Network}OnionSeeds.txt"));

            onions.Shuffle();
            foreach (var onion in onions.Take(60))
            {
                if (NBitcoin.Utils.TryParseEndpoint(onion, Network.DefaultPort, out var endpoint))
                {
                    await addressManager.AddAsync(endpoint);
                }
            }
        }
示例#2
0
        private async Task LoadGroup()
        {
            AddressManager manager = new AddressManager();
            await manager.AddAsync(_ChainConfiguration.NodeEndpoint);

            NodesGroup group = new NodesGroup(_Network.NBitcoinNetwork, new NodeConnectionParameters()
            {
                Services          = NodeServices.Nothing,
                IsRelay           = true,
                TemplateBehaviors =
                {
                    new AddressManagerBehavior(manager)
                    {
                        PeersToDiscover = 1,
                        Mode            = AddressManagerBehaviorMode.None
                    },
                    new ExplorerBehavior(_Repository, _Chain, _AddressPoolService, _EventAggregator)
                    {
                        StartHeight = _ChainConfiguration.StartHeight
                    },
                    new SlimChainBehavior(_Chain),
                    new PingPongBehavior()
                }
            });

            group.AllowSameGroup        = true;
            group.MaximumNodeConnection = 1;

            var task = WaitConnected(group);

            group.Connect();

            try
            {
                await task;
            }
            catch (Exception ex)
            {
                Logs.Configuration.LogError(ex, $"{_Network.CryptoCode}: Failure to connect to the bitcoin node (P2P)");
                throw;
            }
            _Group = group;

            group.ConnectedNodes.Added   += ConnectedNodes_Changed;
            group.ConnectedNodes.Removed += ConnectedNodes_Changed;

            // !Hack. ExplorerBehavior.AttachCore is async and calling the repository.
            // Because the repository is single thread, calling a ping make sure that AttachCore
            // has fully ran.
            // Without this hack, NBXplorer takes sometimes 1 min to go from Synching to Ready state
            await _Repository.Ping();
        }
示例#3
0
        private async Task AddKnownBitcoinFullNodeAsHiddenServiceAsync(AddressManager addressManager)
        {
            if (Network == Network.RegTest)
            {
                return;
            }

            // curl -s https://bitnodes.21.co/api/v1/snapshots/latest/ | egrep -o '[a-z0-9]{16}\.onion:?[0-9]*' | sort -ru
            // Then filtered to include only /Satoshi:0.17.x
            var fullBaseDirectory = EnvironmentHelpers.GetFullBaseDirectory();

            var onions = await File.ReadAllLinesAsync(Path.Combine(fullBaseDirectory, "OnionSeeds", $"{Network}OnionSeeds.txt"));

            onions.Shuffle();
            foreach (var onion in onions.Take(60))
            {
                if (Utils.TryParseEndpoint(onion, Network.DefaultPort, out var endpoint))
                {
                    await addressManager.AddAsync(endpoint);
                }
            }
        }
示例#4
0
        public void Listen(ConcurrentChain chain = null)
        {
            ListenerTrace.Info($"Connecting to node {_Configuration.Indexer.Node}");
            var ip = Utils.ParseEndpoint(string.IsNullOrWhiteSpace(_Configuration.Indexer.Node) ? "127.0.0.1" : _Configuration.Indexer.Node, Configuration.Indexer.Network.DefaultPort);

            ListenerTrace.Info($"Connecting to node ip {ip.ToEndpointString()}");
            var node = Node.Connect(Configuration.Indexer.Network, ip);

            ListenerTrace.Info($"Connected, trying handshake...");
            node.VersionHandshake();
            ListenerTrace.Info($"Hanshaked");
            node.Disconnect();

            _Chain   = new ConcurrentChain(_Configuration.Indexer.Network);
            _Indexer = Configuration.Indexer.CreateIndexer();
            if (chain == null)
            {
                chain = new ConcurrentChain(_Configuration.Indexer.Network);
            }
            _Chain = chain;
            ListenerTrace.Info("Fetching headers from " + _Chain.Tip.Height + " (from azure)");
            var client = Configuration.Indexer.CreateIndexerClient();

            client.SynchronizeChain(chain, default(CancellationToken)).GetAwaiter().GetResult();
            ListenerTrace.Info("Headers fetched tip " + _Chain.Tip.Height);

            _Disposables.Add(_IndexerScheduler = new CustomThreadPoolTaskScheduler(50, 100, "Indexing Threads"));
            _Indexer.TaskScheduler             = _IndexerScheduler;

            _Group = new NodesGroup(Configuration.Indexer.Network);
            _Disposables.Add(_Group);
            _Group.AllowSameGroup        = true;
            _Group.MaximumNodeConnection = 2;
            AddressManager addrman = new AddressManager();


            addrman.AddAsync(ip, IPAddress.Parse("127.0.0.1")).GetAwaiter().GetResult();

            _Group.NodeConnectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addrman)
            {
                Mode = AddressManagerBehaviorMode.None
            });
            _Group.NodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(_Chain)
            {
                SkipPoWCheck = true
            });
            _Group.NodeConnectionParameters.TemplateBehaviors.Add(new Behavior(this));



            ListenerTrace.Info("Fetching wallet rules...");
            _Wallets = _Configuration.Indexer.CreateIndexerClient().GetAllWalletRules();
            ListenerTrace.Info("Wallet rules fetched");

            ListenerTrace.Info("Fetching wallet subscriptions...");
            _Subscriptions = new SubscriptionCollection(_Configuration.GetSubscriptionsTable().Read());
            ListenerTrace.Info("Subscriptions fetched");
            _Group.Connect();

            ListenerTrace.Info("Fetching transactions to broadcast...");

            _Disposables.Add(
                Configuration
                .Topics
                .BroadcastedTransactions
                .CreateConsumer("listener", true)
                .EnsureSubscriptionExists()
                .OnMessage((tx, ctl) =>
            {
                uint256 hash = null;
                var repo     = Configuration.Indexer.CreateIndexerClient();
                var rejects  = Configuration.GetRejectTable();
                try
                {
                    hash          = tx.Transaction.GetHash();
                    var indexedTx = repo.GetTransaction(hash);
                    ListenerTrace.Info("Broadcasting " + hash);
                    var reject = rejects.ReadOne(hash.ToString());
                    if (reject != null)
                    {
                        ListenerTrace.Info("Abort broadcasting of rejected");
                        return;
                    }

                    if (_Broadcasting.Count > 1000)
                    {
                        _Broadcasting.Clear();
                    }

                    _Broadcasting.TryAdd(hash, tx.Transaction);
                    if (indexedTx == null || !indexedTx.BlockIds.Any(id => Chain.Contains(id)))
                    {
                        var unused = SendMessageAsync(tx.Transaction);
                    }
                    var reschedule = new[]
                    {
                        TimeSpan.FromMinutes(5),
                        TimeSpan.FromMinutes(10),
                        TimeSpan.FromHours(1),
                        TimeSpan.FromHours(6),
                        TimeSpan.FromHours(24),
                    };
                    if (tx.Tried <= reschedule.Length - 1)
                    {
                        ctl.RescheduleIn(reschedule[tx.Tried]);
                        tx.Tried++;
                    }
                }
                catch (Exception ex)
                {
                    if (!_Disposed)
                    {
                        LastException = ex;
                        ListenerTrace.Error("Error for new broadcasted transaction " + hash, ex);
                        throw;
                    }
                }
            }));
            ListenerTrace.Info("Transactions to broadcast fetched");

            _Disposables.Add(_Configuration
                             .Topics
                             .SubscriptionChanges
                             .EnsureSubscriptionExists()
                             .AddUnhandledExceptionHandler(ExceptionOnMessagePump)
                             .OnMessage(c =>
            {
                using (_SubscriptionSlimLock.LockWrite())
                {
                    if (c.Added)
                    {
                        _Subscriptions.Add(c.Subscription);
                    }
                    else
                    {
                        _Subscriptions.Remove(c.Subscription.Id);
                    }
                }
            }));

            _Disposables.Add(_Configuration
                             .Topics
                             .SendNotifications
                             .AddUnhandledExceptionHandler(ExceptionOnMessagePump)
                             .OnMessageAsync((n, act) =>
            {
                return(SendAsync(n, act).ContinueWith(t =>
                {
                    if (!_Disposed)
                    {
                        if (t.Exception != null)
                        {
                            LastException = t.Exception;
                        }
                    }
                }));
            }, new OnMessageOptions()
            {
                MaxConcurrentCalls = 1000,
                AutoComplete       = true,
                AutoRenewTimeout   = TimeSpan.Zero
            }));

            _Disposables.Add(Configuration
                             .Topics
                             .AddedAddresses
                             .CreateConsumer("updater", true)
                             .EnsureSubscriptionExists()
                             .AddUnhandledExceptionHandler(ExceptionOnMessagePump)
                             .OnMessage(evt =>
            {
                if (evt == null)
                {
                    return;
                }
                ListenerTrace.Info("New wallet rule");
                using (_WalletsSlimLock.LockWrite())
                {
                    foreach (var address in evt)
                    {
                        _Wallets.Add(address.CreateWalletRuleEntry(Network));
                    }
                }
            }));
        }