public void AddNodeAddress(IPEndPoint endpoint)
        {
            AddressManager addrman = AddressManagerBehavior.GetAddrman(this.AddNodeNodeGroup.NodeConnectionParameters);

            addrman.Add(new NetworkAddress(endpoint));
            this.AddNodeNodeGroup.MaximumNodeConnection++;
        }
Example #2
0
        public void CanMaintainConnectionToNodes()
        {
            using (NodeServerTester servers = new NodeServerTester(Network.TestNet))
            {
                servers.Server1.InboundNodeConnectionParameters.Services = NodeServices.Network;
                AddressManagerBehavior behavior = new AddressManagerBehavior(new AddressManager());
                behavior.AddressManager.Add(new NetworkAddress(servers.Server1.ExternalEndpoint), IPAddress.Parse("127.0.0.1"));
                NodeConnectionParameters parameters = new NodeConnectionParameters();
                parameters.TemplateBehaviors.Add(behavior);
                NodesGroup connected = new NodesGroup(Network.TestNet, parameters, new NodeRequirement()
                {
                    RequiredServices = NodeServices.Network
                });
                connected.AllowSameGroup        = true;
                connected.MaximumNodeConnection = 2;
                connected.Connect();

                TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2);

                //Server crash abruptly
                servers.Server1.ConnectedNodes.First().Disconnect();
                TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1);

                //Reconnect ?
                TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2);

                //Client crash abruptly
                connected.ConnectedNodes.First().Disconnect();
                TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1);

                //Reconnect ?
                TestUtils.Eventually(() => connected.ConnectedNodes.Count == 2);
            }
        }
Example #3
0
        /// <summary>
        /// Connect to a random node on the network
        /// </summary>
        /// <param name="network">The network to connect to</param>
        /// <param name="parameters">The parameters used by the found node, use AddressManagerBehavior.GetAddrman for finding peers</param>
        /// <param name="connectedAddresses">The already connected addresses, the new address will be select outside of existing groups</param>
        /// <returns></returns>
        public static Node Connect(NetworkInfo network, NodeConnectionParameters parameters = null, IPAddress[] connectedAddresses = null)
        {
            connectedAddresses = connectedAddresses ?? new IPAddress[0];
            parameters         = parameters ?? new NodeConnectionParameters();
            var            addrman = AddressManagerBehavior.GetAddrman(parameters) ?? new AddressManager();
            DateTimeOffset start   = DateTimeOffset.UtcNow;

            while (true)
            {
                parameters.ConnectCancellation.ThrowIfCancellationRequested();
                if (addrman.Count == 0 || DateTimeOffset.UtcNow - start > TimeSpan.FromSeconds(10))
                {
                    addrman.DiscoverPeers(network, parameters);
                    start = DateTimeOffset.UtcNow;
                }
                NetworkAddress addr = null;
                while (true)
                {
                    addr = addrman.Select();
                    if (addr == null)
                    {
                        break;
                    }
                    if (!addr.Endpoint.Address.IsValid())
                    {
                        continue;
                    }
                    var groupExist = connectedAddresses.Any(a => a.GetGroup().SequenceEqual(addr.Endpoint.Address.GetGroup()));
                    if (groupExist)
                    {
                        continue;
                    }
                    break;
                }
                if (addr == null)
                {
                    continue;
                }
                try
                {
                    var timeout = new CancellationTokenSource(5000);
                    var param2  = parameters.Clone();
                    param2.ConnectCancellation = CancellationTokenSource.CreateLinkedTokenSource(parameters.ConnectCancellation, timeout.Token).Token;
                    var node = Node.Connect(network, addr.Endpoint, param2);
                    return(node);
                }
                catch (OperationCanceledException ex)
                {
                    if (ex.CancellationToken == parameters.ConnectCancellation)
                    {
                        throw;
                    }
                }
                catch (SocketException)
                {
                    parameters.ConnectCancellation.WaitHandle.WaitOne(500);
                }
            }
        }
Example #4
0
        internal void StartConnecting()
        {
            if (_Disconnect.IsCancellationRequested)
            {
                return;
            }
            if (_ConnectedNodes.Count >= MaximumNodeConnection)
            {
                return;
            }
            if (_Connecting)
            {
                return;
            }
            Task.Factory.StartNew(() =>
            {
                if (Monitor.TryEnter(cs))
                {
                    _Connecting = true;
                    try
                    {
                        while (!_Disconnect.IsCancellationRequested && _ConnectedNodes.Count < MaximumNodeConnection)
                        {
                            Logs.NodeServer.LogInformation("Connected nodes {connectedNodeCount} / {maximumNodeCount} ", _ConnectedNodes.Count, MaximumNodeConnection);
                            var parameters = _ConnectionParameters.Clone();
                            parameters.TemplateBehaviors.Add(new NodesGroupBehavior(this));
                            parameters.ConnectCancellation = _Disconnect.Token;
                            var addrman = AddressManagerBehavior.GetAddrman(parameters);

                            if (addrman == null)
                            {
                                addrman = _DefaultAddressManager;
                                AddressManagerBehavior.SetAddrman(parameters, addrman);
                            }

                            Node node = null;
                            try
                            {
                                var groupSelector = CustomGroupSelector != null ? CustomGroupSelector :
                                                    AllowSameGroup ? WellKnownGroupSelectors.ByRandom : null;

                                var connectedPeers = _ConnectedNodes.Where(n => n.Peer is { }).Select(n => n.Peer.Endpoint).ToArray();
                                node = Node.Connect(_Network, parameters, connectedPeers, groupSelector);
                                using (var timeout = CancellationTokenSource.CreateLinkedTokenSource(_Disconnect.Token))
                                {
                                    timeout.CancelAfter(5000);
                                    node.VersionHandshake(_Requirements, timeout.Token);
                                    Logs.NodeServer.LogInformation("Node successfully connected to and handshaked");
                                }
                            }
                            catch (OperationCanceledException ex)
                            {
                                if (_Disconnect.Token.IsCancellationRequested)
                                {
                                    break;
                                }
                                Logs.NodeServer.LogError(default, ex, "Timeout for picked node");
Example #5
0
        public NodeManager(BlockChain.BlockChain blockChain)
        {
            _BlockChain = blockChain;
            var addressManager = new AddressManager();

            _NodeConnectionParameters = new NodeConnectionParameters();
            var addressManagerBehavior = new AddressManagerBehavior(addressManager);

            _NodeConnectionParameters.TemplateBehaviors.Add(addressManagerBehavior);
        }
Example #6
0
        /// <summary>
        /// Configure the components of the wallet
        /// </summary>
        /// <param name="group">The group to use</param>
        public void Configure(NodesGroup group)
        {
            if (group == null)
            {
                throw new ArgumentNullException("group");
            }

            var parameters = group.NodeConnectionParameters;

            group.Requirements.MinVersion        = ProtocolVersion.PROTOCOL_VERSION;
            group.Requirements.RequiredServices |= NodeServices.Network;

            var chain = parameters.TemplateBehaviors.Find <ChainBehavior>();

            if (chain == null)
            {
                chain = new ChainBehavior(new ConcurrentChain(_Parameters.Network));
                parameters.TemplateBehaviors.Add(chain);
            }
            if (chain.Chain.Genesis.HashBlock != _Parameters.Network.GetGenesis().GetHash())
            {
                throw new InvalidOperationException("ChainBehavior with invalid network chain detected");
            }

            var addrman = parameters.TemplateBehaviors.Find <AddressManagerBehavior>();

            if (addrman == null)
            {
                addrman = new AddressManagerBehavior(new AddressManager());
                parameters.TemplateBehaviors.Add(addrman);
            }

            var tracker = parameters.TemplateBehaviors.Find <TrackerBehavior>();

            if (tracker == null)
            {
                tracker = new TrackerBehavior(new Tracker(), chain.Chain);
                parameters.TemplateBehaviors.Add(tracker);
            }
            var wallet = FindWalletBehavior(parameters.TemplateBehaviors);

            if (wallet == null)
            {
                wallet = new WalletBehavior(this);
                parameters.TemplateBehaviors.Add(wallet);
            }

            _Group = group;
            if (_ListenedTracker != null)
            {
                _ListenedTracker.NewOperation -= _ListenerTracked_NewOperation;
            }
            _ListenedTracker = tracker.Tracker;
            _ListenedTracker.NewOperation += _ListenerTracked_NewOperation;
        }
Example #7
0
        public void AddNodeAddress(IPEndPoint endpoint)
        {
            this.logger.LogTrace("({0}:'{1}')", nameof(endpoint), endpoint);

            AddressManager addrman = AddressManagerBehavior.GetAddrman(this.AddNodeNodeGroup.NodeConnectionParameters);

            addrman.Add(new NetworkAddress(endpoint));
            this.AddNodeNodeGroup.MaximumNodeConnection++;

            this.logger.LogTrace("(-)");
        }
Example #8
0
        public static Node Handshake(NodeServer originServer, NodeServer destServer, String desc)
        {
            NodeConnectionParameters nodeConnectionParameters = new NodeConnectionParameters();

            NBitcoin.Protocol.AddressManager addressManager = new NBitcoin.Protocol.AddressManager();
            //	Console.WriteLine ("Address Manager of Handshaked Node " + desc + " is " + addressManager.GetHashCode ());

            AddressManagerBehavior addressManagerBehavior = new AddressManagerBehavior(addressManager);

            nodeConnectionParameters.TemplateBehaviors.Add(addressManagerBehavior);
            Node node = Node.Connect(destServer.Network, destServer.ExternalEndpoint, nodeConnectionParameters);

            node.Advertize             = true;
            node.MyVersion.AddressFrom = originServer.ExternalEndpoint;
            node.VersionHandshake();

            return(node);
        }
Example #9
0
        protected Node Connect(NodeServer originServer, NodeServer destServer)
        {
            NodeConnectionParameters nodeConnectionParameters = new NodeConnectionParameters();

            AddressManager addressManager = new AddressManager();

            AddressManagerBehavior addressManagerBehavior = new AddressManagerBehavior(addressManager);

            nodeConnectionParameters.TemplateBehaviors.Add(addressManagerBehavior);
            //	nodeConnectionParameters.AddressFrom = originServer.ExternalEndpoint;
            Node node = Node.Connect(destServer.Network, destServer.ExternalEndpoint, nodeConnectionParameters);

            Assert.AreEqual(NodeState.Connected, node.State);

            Trace.Information($"\n\nConncted from {originServer.ExternalEndpoint} to {destServer.ExternalEndpoint}\n\n");

            return(node);
        }
Example #10
0
        public Server(IPAddress externalAddress, NetworkInfo network, NodeConnectionParameters nodeConnectionParameters)
        {
            _Server = new NodeServer(network, internalPort: network.DefaultPort);
            OwnResource(_Server);

            if (externalAddress != null)
            {
                var            externalEndpoint = new IPEndPoint(externalAddress, network.DefaultPort);
                AddressManager addressManager   = AddressManagerBehavior.GetAddrman(nodeConnectionParameters);
                addressManager.Add(new NetworkAddress(externalEndpoint));
                addressManager.Connected(new NetworkAddress(externalEndpoint));
                _Server.ExternalEndpoint = externalEndpoint;
            }

            _Server.InboundNodeConnectionParameters = nodeConnectionParameters;
            _Server.AllowLocalPeers = false;             //TODO

            NodeServerTrace.Information($"Server setup at {externalAddress}");
        }
Example #11
0
        private static NodesGroup CreateGroup(IEnumerable <CoreNode> nodes, int connections)
        {
            AddressManagerBehavior behavior = new AddressManagerBehavior(new AddressManager());

            foreach (var node in nodes)
            {
                behavior.AddressManager.Add(new NetworkAddress(node.Endpoint), IPAddress.Parse("127.0.0.1"));
            }
            NodeConnectionParameters parameters = new NodeConnectionParameters();

            parameters.TemplateBehaviors.Add(behavior);
            Wallet.ConfigureDefaultNodeConnectionParameters(parameters);
            parameters.IsTrusted = true;
            NodesGroup connected = new NodesGroup(Network.RegTest, parameters);

            connected.AllowSameGroup        = true;
            connected.MaximumNodeConnection = connections;
            return(connected);
        }
Example #12
0
        public Server(IResourceOwner resourceOwner, IPEndPoint externalEndpoint, NBitcoin.Network network)
        {
            _Server = new NodeServer(network, internalPort: externalEndpoint.Port);
            resourceOwner.OwnResource(_Server);

            NodeConnectionParameters nodeConnectionParameters = new NodeConnectionParameters();

            NBitcoin.Protocol.AddressManager addressManager = AddressManager.Instance.GetBitcoinAddressManager();             // new NBitcoin.Protocol.AddressManager ();

            var addressManagerBehavior = new AddressManagerBehavior(addressManager);

            //	addressManagerBehavior.Mode = hasExternal ? AddressManagerBehaviorMode.AdvertizeDiscover : AddressManagerBehaviorMode.Discover;
            nodeConnectionParameters.TemplateBehaviors.Add(addressManagerBehavior);

            _Server.InboundNodeConnectionParameters = nodeConnectionParameters;
            _Server.AllowLocalPeers  = true;            //TODO
            _Server.ExternalEndpoint = externalEndpoint;

            Trace.Information($"Server setup at {externalEndpoint}");
        }
Example #13
0
        private static NodesGroup CreateGroup(NodeServerTester servers, int connections)
        {
            AddressManagerBehavior behavior = new AddressManagerBehavior(new AddressManager());

            if (connections == 1)
            {
                behavior.AddressManager.Add(new NetworkAddress(servers.Server1.ExternalEndpoint), IPAddress.Parse("127.0.0.1"));
            }
            if (connections > 1)
            {
                behavior.AddressManager.Add(new NetworkAddress(servers.Server2.ExternalEndpoint), IPAddress.Parse("127.0.0.1"));
            }
            NodeConnectionParameters parameters = new NodeConnectionParameters();

            parameters.TemplateBehaviors.Add(behavior);
            Wallet.ConfigureDefaultNodeConnectionParameters(parameters);
            parameters.IsTrusted = true;
            NodesGroup connected = new NodesGroup(Network.TestNet, parameters);

            connected.AllowSameGroup        = true;
            connected.MaximumNodeConnection = connections;
            return(connected);
        }
Example #14
0
        private AddressManager GetAddressManager()
        {
            if (_connectionParameters != null)
            {
                AddressManagerBehavior behaviour = _connectionParameters.TemplateBehaviors.Find <AddressManagerBehavior>();

                if (behaviour != null)
                {
                    return(behaviour.AddressManager);
                }
            }

            try
            {
                lock (_padlock)
                {
                    return(AddressManager.LoadPeerFile(AddrmanFile));
                }
            }
            catch
            {
                return(new AddressManager());
            }
        }
Example #15
0
 protected bool AddressManagerContains(Node node, IPEndPoint ipEndPoint)
 {
     return(AddressManagerContains(AddressManagerBehavior.GetAddrman(node), ipEndPoint));
 }
Example #16
0
        private void DumpCoins(BitcoinAddress destination, IEnumerable <Coin> coins, IEnumerable <Key> keys)
        {
            var     total   = coins.Select(u => u.Amount).Sum();
            var     fee     = Money.Zero;
            FeeRate feeRate = null;

            try
            {
                feeRate = RPCClient.EstimateFeeRate(6);                 //BCC having few fees, this will confirm fast
            }
            catch
            {
                if (RPCClient.Network == Network.RegTest)
                {
                    feeRate = new FeeRate(Money.Satoshis(30), 1);
                }
                else
                {
                    Logs.Main.LogWarning("Fee estimation unavailable, you need to wait Bitcoin Core to properly sync and retry to dump");
                    return;
                }
            }
            TransactionBuilder builder = new TransactionBuilder();

            builder.AddCoins(coins);
            builder.Send(destination, total);
            try
            {
                builder.SendEstimatedFees(feeRate);
                builder.BuildTransaction(false);
            }
            catch (NotEnoughFundsException ex)
            {
                fee = (Money)ex.Missing;
            }

            builder = new TransactionBuilder();
            builder.AddKeys(keys.ToArray());
            builder.AddCoins(coins);
            builder.Send(destination, total - fee);
            builder.SendFees(fee);
            var dumpTransaction = builder.BuildTransaction(true, SigHash.ForkId | SigHash.All);

            Logs.Main.LogInformation("Dump transaction created " + dumpTransaction.ToHex());

            Logs.Main.LogInformation("Dump transaction ID " + dumpTransaction.GetHash());
            //repository.lock(coins.select(c => c.outpoint).toarray(), dumptransaction.gethash());
            Thread.Sleep(1000);
            while (true)
            {
                Console.WriteLine("Are you sure to dump " + coins.Select(c => c.Amount).Sum().ToString() + " BCash coin to " + destination.ToString() + " ? (type `yes` to continue)");
                var response = Console.ReadLine();
                if (response.Equals("yes", StringComparison.OrdinalIgnoreCase))
                {
                    break;
                }
            }

            Logs.Main.LogInformation("Connecting to a BCC node...");

            AddressManagerBehavior addrman = new AddressManagerBehavior(new AddressManager());

            addrman.PeersToDiscover = 10;
            addrman.Mode            = AddressManagerBehaviorMode.Discover;
            NodesGroup group = new NodesGroup(RPCClient.Network, new NodeConnectionParameters()
            {
                IsRelay           = false,
                Services          = NodeServices.Nothing | NodeServices.NODE_BITCOIN_CASH,
                TemplateBehaviors = { addrman },
                UserAgent         = "BCCSpliter",
                Advertize         = false
            }, new NodeRequirement()
            {
                RequiredServices = NodeServices.NODE_BITCOIN_CASH
            });

            group.MaximumNodeConnection = 1;

            if (Configuration.BCCEndpoint != null)
            {
                addrman.PeersToDiscover = 1;
                addrman.Mode            = AddressManagerBehaviorMode.None;
                addrman.AddressManager.Add(new NetworkAddress(Configuration.BCCEndpoint), IPAddress.Parse("127.0.0.1"));
                group.CustomGroupSelector = WellKnownGroupSelectors.ByEndpoint;
                group.AllowSameGroup      = true;
            }

            group.ConnectedNodes.Added += (s, e) =>
            {
                Logs.Main.LogInformation("Connected to " + e.Node.RemoteSocketEndpoint);
                Logs.Main.LogInformation("Broadcasting...");
                e.Node.SendMessageAsync(new InvPayload(new InventoryVector(InventoryType.MSG_TX, dumpTransaction.GetHash())));
                e.Node.SendMessageAsync(new TxPayload(dumpTransaction));
                CancellationTokenSource cts = new CancellationTokenSource();
                cts.CancelAfter(10000);
                try
                {
                    e.Node.PingPong(cts.Token);
                }
                catch (Exception ex)
                {
                    Logs.Main.LogWarning("Error while broadcasting transaction, retrying with another node...");
                    e.Node.Disconnect("Error while broadcasting transaction", ex);
                    return;
                }
                Logs.Main.LogInformation("Broadcasted " + dumpTransaction.GetHash());
                group.Disconnect();
                group.Dispose();
            };

            group.Connect();
        }
Example #17
0
        private static async Task <AddressManagerBehavior> InitializeAddressManagerBehaviorAsync()
        {
            var needsToDiscoverPeers = true;

            if (Network == Network.RegTest)
            {
                AddressManager = new AddressManager();
                Logger.LogInfo <AddressManager>($"Fake {nameof(AddressManager)} is initialized on the RegTest.");
            }
            else
            {
                try
                {
                    AddressManager = await NBitcoinHelpers.LoadAddressManagerFromPeerFileAsync(AddressManagerFilePath);

                    // The most of the times we don't need to discover new peers. Instead, we can connect to
                    // some of those that we already discovered in the past. In this case we assume that we
                    // assume that discovering new peers could be necessary if out address manager has less
                    // than 500 addresses. A 500 addresses could be okay because previously we tried with
                    // 200 and only one user reported he/she was not able to connect (there could be many others,
                    // of course).
                    // On the other side, increasing this number forces users that do not need to discover more peers
                    // to spend resources (CPU/bandwith) to discover new peers.
                    needsToDiscoverPeers = Config.UseTor == true || AddressManager.Count < 500;
                    Logger.LogInfo <AddressManager>($"Loaded {nameof(AddressManager)} from `{AddressManagerFilePath}`.");
                }
                catch (DirectoryNotFoundException ex)
                {
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one.");
                    Logger.LogTrace <AddressManager>(ex);
                    AddressManager = new AddressManager();
                }
                catch (FileNotFoundException ex)
                {
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one.");
                    Logger.LogTrace <AddressManager>(ex);
                    AddressManager = new AddressManager();
                }
                catch (OverflowException ex)
                {
                    // https://github.com/zkSNACKs/WalletWasabi/issues/712
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} has thrown `{nameof(OverflowException)}`. Attempting to autocorrect.");
                    File.Delete(AddressManagerFilePath);
                    Logger.LogTrace <AddressManager>(ex);
                    AddressManager = new AddressManager();
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} autocorrection is successful.");
                }
                catch (FormatException ex)
                {
                    // https://github.com/zkSNACKs/WalletWasabi/issues/880
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} has thrown `{nameof(FormatException)}`. Attempting to autocorrect.");
                    File.Delete(AddressManagerFilePath);
                    Logger.LogTrace <AddressManager>(ex);
                    AddressManager = new AddressManager();
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} autocorrection is successful.");
                }
            }

            var addressManagerBehavior = new AddressManagerBehavior(AddressManager)
            {
                Mode = needsToDiscoverPeers ? AddressManagerBehaviorMode.Discover : AddressManagerBehaviorMode.None
            };

            return(addressManagerBehavior);
        }
        public void Start()
        {
            this.parameters.UserAgent = "StratisBitcoin:" + GetVersion();
            this.parameters.Version   = this.NodeSettings.ProtocolVersion;
            if (this.connectionManagerSettings.Connect.Count == 0)
            {
                NodeConnectionParameters cloneParameters = this.parameters.Clone();
                cloneParameters.TemplateBehaviors.Add(new ConnectionManagerBehavior(false, this));
                this.DiscoveredNodeGroup = CreateNodeGroup(cloneParameters, this.discoveredNodeRequiredService);
                this.DiscoveredNodeGroup.CustomGroupSelector = WellKnownGroupSelectors.ByNetwork;                 //is the default, but I want to use it
                this.DiscoveredNodeGroup.Connect();
            }
            else
            {
                NodeConnectionParameters cloneParameters = this.parameters.Clone();
                cloneParameters.TemplateBehaviors.Add(new ConnectionManagerBehavior(false, this));
                cloneParameters.TemplateBehaviors.Remove <AddressManagerBehavior>();
                var addrman = new AddressManager();
                addrman.Add(this.connectionManagerSettings.Connect.Select(c => new NetworkAddress(c)).ToArray(), IPAddress.Loopback);
                var addrmanBehavior = new AddressManagerBehavior(addrman);
                addrmanBehavior.Mode = AddressManagerBehaviorMode.None;
                cloneParameters.TemplateBehaviors.Add(addrmanBehavior);

                this.ConnectNodeGroup = CreateNodeGroup(cloneParameters, NodeServices.Nothing);
                this.ConnectNodeGroup.MaximumNodeConnection = this.connectionManagerSettings.Connect.Count;
                this.ConnectNodeGroup.CustomGroupSelector   = WellKnownGroupSelectors.ByEndpoint;
                this.ConnectNodeGroup.Connect();
            }

            {
                NodeConnectionParameters cloneParameters = this.parameters.Clone();
                cloneParameters.TemplateBehaviors.Add(new ConnectionManagerBehavior(false, this));
                cloneParameters.TemplateBehaviors.Remove <AddressManagerBehavior>();
                var addrman = new AddressManager();
                addrman.Add(this.connectionManagerSettings.AddNode.Select(c => new NetworkAddress(c)).ToArray(), IPAddress.Loopback);
                var addrmanBehavior = new AddressManagerBehavior(addrman);
                addrmanBehavior.Mode = AddressManagerBehaviorMode.AdvertizeDiscover;
                cloneParameters.TemplateBehaviors.Add(addrmanBehavior);

                this.AddNodeNodeGroup = CreateNodeGroup(cloneParameters, NodeServices.Nothing);
                this.AddNodeNodeGroup.MaximumNodeConnection = this.connectionManagerSettings.AddNode.Count;
                this.AddNodeNodeGroup.CustomGroupSelector   = WellKnownGroupSelectors.ByEndpoint;
                this.AddNodeNodeGroup.Connect();
            }

            StringBuilder logs = new StringBuilder();

            logs.AppendLine("Node listening on:");
            foreach (NodeServerEndpoint listen in this.connectionManagerSettings.Listen)
            {
                NodeConnectionParameters cloneParameters = this.parameters.Clone();
                var server = new NodeServer(this.Network);

                server.LocalEndpoint    = listen.Endpoint;
                server.ExternalEndpoint = this.connectionManagerSettings.ExternalEndpoint;
                this.Servers.Add(server);
                cloneParameters.TemplateBehaviors.Add(new ConnectionManagerBehavior(true, this)
                {
                    Whitelisted = listen.Whitelisted
                });
                server.InboundNodeConnectionParameters = cloneParameters;
                server.Listen();
                logs.Append(listen.Endpoint.Address + ":" + listen.Endpoint.Port);
                if (listen.Whitelisted)
                {
                    logs.Append(" (whitelisted)");
                }
                logs.AppendLine();
            }
            Logs.ConnectionManager.LogInformation(logs.ToString());
        }
Example #19
0
        public static void InitializeNoWallet()
        {
            WalletService  = null;
            ChaumianClient = null;

            AppDomain.CurrentDomain.ProcessExit += async(s, e) => await TryDesperateDequeueAllCoinsAsync();

            Console.CancelKeyPress += async(s, e) =>
            {
                e.Cancel = true;
                Logger.LogWarning("Process was signaled for killing.", nameof(Global));
                await TryDesperateDequeueAllCoinsAsync();

                Dispatcher.UIThread.Post(() =>
                {
                    Application.Current.MainWindow.Close();
                });
            };

            var addressManagerFolderPath = Path.Combine(DataDir, "AddressManager");

            AddressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{Network}.dat");
            var blocksFolderPath     = Path.Combine(DataDir, $"Blocks{Network}");
            var connectionParameters = new NodeConnectionParameters();

            AddressManager = null;
            TorManager     = null;

            TorManager = new TorProcessManager(Config.GetTorSocks5EndPoint(), TorLogsFile);
            TorManager.Start(false, DataDir);
            var fallbackRequestTestUri = new Uri(Config.GetFallbackBackendUri(), "/api/software/versions");

            TorManager.StartMonitor(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), DataDir, fallbackRequestTestUri);

            Logger.LogInfo <TorProcessManager>($"{nameof(TorProcessManager)} is initialized.");

            var needsToDiscoverPeers = true;

            if (Network == Network.RegTest)
            {
                AddressManager = new AddressManager();
                Logger.LogInfo <AddressManager>($"Fake {nameof(AddressManager)} is initialized on the RegTest.");
            }
            else
            {
                try
                {
                    AddressManager = AddressManager.LoadPeerFile(AddressManagerFilePath);

                    // The most of the times we don't need to discover new peers. Instead, we can connect to
                    // some of those that we already discovered in the past. In this case we assume that we
                    // assume that discovering new peers could be necessary if out address manager has less
                    // than 500 addresses. A 500 addresses could be okay because previously we tried with
                    // 200 and only one user reported he/she was not able to connect (there could be many others,
                    // of course).
                    // On the other side, increasing this number forces users that do not need to discover more peers
                    // to spend resources (CPU/bandwith) to discover new peers.
                    needsToDiscoverPeers = AddressManager.Count < 500;
                    Logger.LogInfo <AddressManager>($"Loaded {nameof(AddressManager)} from `{AddressManagerFilePath}`.");
                }
                catch (DirectoryNotFoundException ex)
                {
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one.");
                    Logger.LogTrace <AddressManager>(ex);
                    AddressManager = new AddressManager();
                }
                catch (FileNotFoundException ex)
                {
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one.");
                    Logger.LogTrace <AddressManager>(ex);
                    AddressManager = new AddressManager();
                }
                catch (OverflowException ex)
                {
                    // https://github.com/zkSNACKs/WalletWasabi/issues/712
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} has thrown `{nameof(OverflowException)}`. Attempting to autocorrect.");
                    File.Delete(AddressManagerFilePath);
                    Logger.LogTrace <AddressManager>(ex);
                    AddressManager = new AddressManager();
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} autocorrection is successful.");
                }
                catch (FormatException ex)
                {
                    // https://github.com/zkSNACKs/WalletWasabi/issues/880
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} has thrown `{nameof(FormatException)}`. Attempting to autocorrect.");
                    File.Delete(AddressManagerFilePath);
                    Logger.LogTrace <AddressManager>(ex);
                    AddressManager = new AddressManager();
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} autocorrection is successful.");
                }
            }

            var addressManagerBehavior = new AddressManagerBehavior(AddressManager)
            {
                Mode = needsToDiscoverPeers ? AddressManagerBehaviorMode.Discover : AddressManagerBehaviorMode.None
            };

            connectionParameters.TemplateBehaviors.Add(addressManagerBehavior);
            MemPoolService = new MemPoolService();
            connectionParameters.TemplateBehaviors.Add(new MemPoolBehavior(MemPoolService));

            if (Network == Network.RegTest)
            {
                Nodes = new NodesGroup(Network, requirements: Constants.NodeRequirements);
                try
                {
                    Node node = Node.Connect(Network.RegTest, new IPEndPoint(IPAddress.Loopback, 18444));
                    Nodes.ConnectedNodes.Add(node);

                    RegTestMemPoolServingNode = Node.Connect(Network.RegTest, new IPEndPoint(IPAddress.Loopback, 18444));

                    RegTestMemPoolServingNode.Behaviors.Add(new MemPoolBehavior(MemPoolService));
                }
                catch (SocketException ex)
                {
                    Logger.LogError(ex, nameof(Global));
                }
            }
            else
            {
                Nodes = new NodesGroup(Network, connectionParameters, requirements: Constants.NodeRequirements);

                RegTestMemPoolServingNode = null;
            }

            Synchronizer = new WasabiSynchronizer(Network, IndexFilePath, Config.GetCurrentBackendUri(), Config.GetTorSocks5EndPoint());

            UpdateChecker = new UpdateChecker(Synchronizer.WasabiClient);

            Nodes.Connect();
            Logger.LogInfo("Start connecting to nodes...");

            if (!(RegTestMemPoolServingNode is null))
            {
                RegTestMemPoolServingNode.VersionHandshake();
                Logger.LogInfo("Start connecting to mempool serving regtest node...");
            }

            var requestInterval = TimeSpan.FromSeconds(30);

            if (Network == Network.RegTest)
            {
                requestInterval = TimeSpan.FromSeconds(5);
            }
            Synchronizer.Start(requestInterval, TimeSpan.FromMinutes(5), 1000);
            Logger.LogInfo("Start synchronizing filters...");
        }
Example #20
0
        public static async Task InitializeNoWalletAsync()
        {
            WalletService  = null;
            ChaumianClient = null;
            AddressManager = null;
            TorManager     = null;

            #region ConfigInitialization

            Config = new Config(Path.Combine(DataDir, "Config.json"));
            await Config.LoadOrCreateDefaultFileAsync();

            Logger.LogInfo <Config>("Config is successfully initialized.");

            #endregion ConfigInitialization

            BitcoinStore = new BitcoinStore();
            var bstoreInitTask           = BitcoinStore.InitializeAsync(Path.Combine(DataDir, "BitcoinStore"), Network);
            var hwiInitTask              = HwiProcessManager.InitializeAsync(DataDir, Network);
            var addressManagerFolderPath = Path.Combine(DataDir, "AddressManager");
            AddressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{Network}.dat");
            var addrManTask = InitializeAddressManagerBehaviorAsync();

            var blocksFolderPath     = Path.Combine(DataDir, $"Blocks{Network}");
            var connectionParameters = new NodeConnectionParameters();

            if (Config.UseTor.Value)
            {
                Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, () => Config.GetCurrentBackendUri(), Config.GetTorSocks5EndPoint());
            }
            else
            {
                Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, Config.GetFallbackBackendUri(), null);
            }

            UpdateChecker = new UpdateChecker(Synchronizer.WasabiClient);

            #region ProcessKillSubscription

            AppDomain.CurrentDomain.ProcessExit += async(s, e) => await TryDesperateDequeueAllCoinsAsync();

            Console.CancelKeyPress += async(s, e) => { e.Cancel = true; await StopAndExitAsync(); };

            #endregion ProcessKillSubscription

            #region TorProcessInitialization

            if (Config.UseTor.Value)
            {
                TorManager = new TorProcessManager(Config.GetTorSocks5EndPoint(), TorLogsFile);
            }
            else
            {
                TorManager = TorProcessManager.Mock();
            }
            TorManager.Start(false, DataDir);

            var fallbackRequestTestUri = new Uri(Config.GetFallbackBackendUri(), "/api/software/versions");
            TorManager.StartMonitor(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), DataDir, fallbackRequestTestUri);

            Logger.LogInfo <TorProcessManager>($"{nameof(TorProcessManager)} is initialized.");

            #endregion TorProcessInitialization

            #region MempoolInitialization

            MemPoolService = new MemPoolService();
            connectionParameters.TemplateBehaviors.Add(new MemPoolBehavior(MemPoolService));

            #endregion MempoolInitialization

            #region HwiProcessInitialization

            try
            {
                await hwiInitTask;
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, nameof(Global));
            }

            #endregion HwiProcessInitialization

            #region BitcoinStoreInitialization

            await bstoreInitTask;

            #endregion BitcoinStoreInitialization

            #region AddressManagerInitialization

            AddressManagerBehavior addressManagerBehavior = await addrManTask;
            connectionParameters.TemplateBehaviors.Add(addressManagerBehavior);

            #endregion AddressManagerInitialization

            #region P2PInitialization

            if (Network == Network.RegTest)
            {
                Nodes = new NodesGroup(Network, requirements: Constants.NodeRequirements);
                try
                {
                    Node node = await Node.ConnectAsync(Network.RegTest, new IPEndPoint(IPAddress.Loopback, 18444));

                    Nodes.ConnectedNodes.Add(node);

                    RegTestMemPoolServingNode = await Node.ConnectAsync(Network.RegTest, new IPEndPoint(IPAddress.Loopback, 18444));

                    RegTestMemPoolServingNode.Behaviors.Add(new MemPoolBehavior(MemPoolService));
                }
                catch (SocketException ex)
                {
                    Logger.LogError(ex, nameof(Global));
                }
            }
            else
            {
                if (Config.UseTor is true)
                {
                    // onlyForOnionHosts: false - Connect to clearnet IPs through Tor, too.
                    connectionParameters.TemplateBehaviors.Add(new SocksSettingsBehavior(Config.GetTorSocks5EndPoint(), onlyForOnionHosts: false, networkCredential: null, streamIsolation: true));
                    // allowOnlyTorEndpoints: true - Connect only to onions and don't connect to clearnet IPs at all.
                    // This of course makes the first setting unneccessary, but it's better if that's around, in case someone wants to tinker here.
                    connectionParameters.EndpointConnector = new DefaultEndpointConnector(allowOnlyTorEndpoints: Network == Network.Main);

                    await AddKnownBitcoinFullNodeAsHiddenServiceAsync(AddressManager);
                }
                Nodes = new NodesGroup(Network, connectionParameters, requirements: Constants.NodeRequirements);

                RegTestMemPoolServingNode = null;
            }

            Nodes.Connect();
            Logger.LogInfo("Start connecting to nodes...");

            if (RegTestMemPoolServingNode != null)
            {
                RegTestMemPoolServingNode.VersionHandshake();
                Logger.LogInfo("Start connecting to mempool serving regtest node...");
            }

            #endregion P2PInitialization

            #region SynchronizerInitialization

            var requestInterval = TimeSpan.FromSeconds(30);
            if (Network == Network.RegTest)
            {
                requestInterval = TimeSpan.FromSeconds(5);
            }

            int maxFiltSyncCount = Network == Network.Main ? 1000 : 10000;             // On testnet, filters are empty, so it's faster to query them together

            Synchronizer.Start(requestInterval, TimeSpan.FromMinutes(5), maxFiltSyncCount);
            Logger.LogInfo("Start synchronizing filters...");

            #endregion SynchronizerInitialization

            #region JsonRpcServerInitialization

            var jsonRpcServerConfig = new JsonRpcServerConfiguration(Config);
            if (jsonRpcServerConfig.IsEnabled)
            {
                RpcServer = new JsonRpcServer(jsonRpcServerConfig);
                RpcServer.Start();
            }

            #endregion JsonRpcServerInitialization

            Initialized = true;
        }
Example #21
0
        public P2pNetwork(Network network, EndPoint fullnodeP2pEndPoint, EndPoint?torSocks5EndPoint, string workDir, BitcoinStore bitcoinStore)
        {
            Network             = network;
            FullnodeP2PEndPoint = fullnodeP2pEndPoint;
            TorSocks5EndPoint   = torSocks5EndPoint;
            WorkDir             = workDir;
            BitcoinStore        = bitcoinStore;

            var userAgent            = Constants.UserAgents.RandomElement();
            var connectionParameters = new NodeConnectionParameters {
                UserAgent = userAgent
            };

            connectionParameters.TemplateBehaviors.Add(BitcoinStore.CreateUntrustedP2pBehavior());

            AddressManagerFilePath = Path.Combine(WorkDir, $"AddressManager{Network}.dat");
            var needsToDiscoverPeers = true;

            if (Network == Network.RegTest)
            {
                AddressManager = new AddressManager();
                Logger.LogInfo($"Fake {nameof(AddressManager)} is initialized on the {Network.RegTest}.");
            }
            else
            {
                try
                {
                    AddressManager = AddressManager.LoadPeerFile(AddressManagerFilePath);

                    // Most of the times we do not need to discover new peers. Instead, we can connect to
                    // some of those that we already discovered in the past. In this case we assume that
                    // discovering new peers could be necessary if our address manager has less
                    // than 500 addresses. 500 addresses could be okay because previously we tried with
                    // 200 and only one user reported he/she was not able to connect (there could be many others,
                    // of course).
                    // On the other side, increasing this number forces users that do not need to discover more peers
                    // to spend resources (CPU/bandwidth) to discover new peers.
                    needsToDiscoverPeers = TorSocks5EndPoint is not null || AddressManager.Count < 500;
                    Logger.LogInfo($"Loaded {nameof(AddressManager)} from `{AddressManagerFilePath}`.");
                }
                catch (DirectoryNotFoundException ex)
                {
                    Logger.LogInfo($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one.");
                    Logger.LogTrace(ex);
                    AddressManager = new AddressManager();
                }
                catch (FileNotFoundException ex)
                {
                    Logger.LogInfo($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one.");
                    Logger.LogTrace(ex);
                    AddressManager = new AddressManager();
                }
                catch (OverflowException ex)
                {
                    // https://github.com/zkSNACKs/WalletWasabi/issues/712
                    Logger.LogInfo($"{nameof(AddressManager)} has thrown `{nameof(OverflowException)}`. Attempting to autocorrect.");
                    File.Delete(AddressManagerFilePath);
                    Logger.LogTrace(ex);
                    AddressManager = new AddressManager();
                    Logger.LogInfo($"{nameof(AddressManager)} autocorrection is successful.");
                }
                catch (FormatException ex)
                {
                    // https://github.com/zkSNACKs/WalletWasabi/issues/880
                    Logger.LogInfo($"{nameof(AddressManager)} has thrown `{nameof(FormatException)}`. Attempting to autocorrect.");
                    File.Delete(AddressManagerFilePath);
                    Logger.LogTrace(ex);
                    AddressManager = new AddressManager();
                    Logger.LogInfo($"{nameof(AddressManager)} autocorrection is successful.");
                }
            }

            var addressManagerBehavior = new AddressManagerBehavior(AddressManager)
            {
                Mode = needsToDiscoverPeers ? AddressManagerBehaviorMode.Discover : AddressManagerBehaviorMode.None
            };

            connectionParameters.TemplateBehaviors.Add(addressManagerBehavior);

            if (Network == Network.RegTest)
            {
                Nodes = new NodesGroup(Network, requirements: Constants.NodeRequirements);
            }
            else
            {
                var maximumNodeConnection       = 12;
                var bestEffortEndpointConnector = new BestEffortEndpointConnector(maximumNodeConnection / 2);
                connectionParameters.EndpointConnector = bestEffortEndpointConnector;
                if (TorSocks5EndPoint is not null)
                {
                    connectionParameters.TemplateBehaviors.Add(new SocksSettingsBehavior(TorSocks5EndPoint, onlyForOnionHosts: false, networkCredential: null, streamIsolation: true));
                }
                var nodes = new NodesGroup(Network, connectionParameters, requirements: Constants.NodeRequirements);
                nodes.ConnectedNodes.Added   += ConnectedNodes_OnAddedOrRemoved;
                nodes.ConnectedNodes.Removed += ConnectedNodes_OnAddedOrRemoved;
                nodes.MaximumNodeConnection   = maximumNodeConnection;

                Nodes = nodes;
            }
        }
Example #22
0
        public async Task InitializeNoWalletAsync(CancellationToken cancellationToken = default)
        {
            AddressManager = null;
            Logger.LogDebug($"{nameof(Global)}.InitializeNoWalletAsync(): Waiting for a lock");
            try
            {
                InitializationStarted = true;

                Logger.LogDebug($"{nameof(Global)}.InitializeNoWalletAsync(): Got lock");

                MemoryCache Cache = new MemoryCache(new MemoryCacheOptions
                {
                    SizeLimit = 1_000,
                    ExpirationScanFrequency = TimeSpan.FromSeconds(30)
                });
                var bstoreInitTask           = _bitcoinStore.InitializeAsync();
                var addressManagerFolderPath = Path.Combine(DataDir, "AddressManager");

                AddressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{Network}.dat");
                var addrManTask = InitializeAddressManagerBehaviorAsync();

                var blocksFolderPath     = Path.Combine(DataDir, $"Blocks{Network}");
                var userAgent            = Constants.UserAgents.RandomElement();
                var connectionParameters = new NodeConnectionParameters {
                    UserAgent = userAgent
                };

                #region TorProcessInitialization

                if (_config.UseTor)
                {
                    await _torManager.StartAsync(ensureRunning : false, DataDir);

                    Logger.LogInfo($"{nameof(_torManager)} is initialized.");
                }

                Logger.LogInfo($"{nameof(Global)}.InitializeNoWalletAsync():{nameof(_torManager)} is initialized.");

                #endregion TorProcessInitialization

                #region BitcoinStoreInitialization

                await bstoreInitTask.ConfigureAwait(false);

                // Make sure that the height of the wallets will not be better than the current height of the filters.
                _walletManager.SetMaxBestHeight(_bitcoinStore.IndexStore.SmartHeaderChain.TipHeight);

                #endregion BitcoinStoreInitialization

                #region MempoolInitialization

                connectionParameters.TemplateBehaviors.Add(_bitcoinStore.CreateUntrustedP2pBehavior());

                #endregion MempoolInitialization

                #region AddressManagerInitialization

                AddressManagerBehavior addressManagerBehavior = await addrManTask.ConfigureAwait(false);

                connectionParameters.TemplateBehaviors.Add(addressManagerBehavior);

                #endregion AddressManagerInitialization

                #region P2PInitialization
                Node regTestMempoolServingNode = null;
                if (Network == Network.RegTest)
                {
                    Nodes = new NodesGroup(Network, requirements: Constants.NodeRequirements);
                    try
                    {
                        EndPoint bitcoinCoreEndpoint = _config.GetBitcoinP2pEndPoint();

                        Node node = await Node.ConnectAsync(NBitcoin.Network.RegTest, bitcoinCoreEndpoint).ConfigureAwait(false);

                        Nodes.ConnectedNodes.Add(node);

                        regTestMempoolServingNode = await Node.ConnectAsync(NBitcoin.Network.RegTest, bitcoinCoreEndpoint).ConfigureAwait(false);

                        regTestMempoolServingNode.Behaviors.Add(_bitcoinStore.CreateUntrustedP2pBehavior());
                    }
                    catch (SocketException ex)
                    {
                        Logger.LogError(ex);
                    }
                }
                else
                {
                    if (_config.UseTor)
                    {
                        // onlyForOnionHosts: false - Connect to clearnet IPs through Tor, too.
                        connectionParameters.TemplateBehaviors.Add(new SocksSettingsBehavior(_config.TorSocks5EndPoint, onlyForOnionHosts: false, networkCredential: null, streamIsolation: true));
                        // allowOnlyTorEndpoints: true - Connect only to onions and don't connect to clearnet IPs at all.
                        // This of course makes the first setting unneccessary, but it's better if that's around, in case someone wants to tinker here.
                        connectionParameters.EndpointConnector = new DefaultEndpointConnector(allowOnlyTorEndpoints: Network == Network.Main);

                        await AddKnownBitcoinFullNodeAsHiddenServiceAsync(AddressManager).ConfigureAwait(false);
                    }
                    Nodes = new NodesGroup(Network, connectionParameters, requirements: Constants.NodeRequirements);
                    Nodes.MaximumNodeConnection = 12;
                    regTestMempoolServingNode   = null;
                }

                Nodes.Connect();
                Logger.LogInfo($"{nameof(Global)}.InitializeNoWalletAsync(): Start connecting to nodes...");

                if (regTestMempoolServingNode != null)
                {
                    regTestMempoolServingNode.VersionHandshake();
                    Logger.LogInfo($"{nameof(Global)}.InitializeNoWalletAsync(): Start connecting to mempool serving regtest node...");
                }

                #endregion P2PInitialization

                #region SynchronizerInitialization

                var requestInterval = TimeSpan.FromSeconds(30);
                if (Network == Network.RegTest)
                {
                    requestInterval = TimeSpan.FromSeconds(5);
                }

                int maxFiltSyncCount = Network == Network.Main ? 1000 : 10000; // On testnet, filters are empty, so it's faster to query them together

                _synchronizer.Start(requestInterval, TimeSpan.FromMinutes(5), maxFiltSyncCount);
                Logger.LogInfo($"{nameof(Global)}.InitializeNoWalletAsync(): Start synchronizing filters...");

                #endregion SynchronizerInitialization

                TransactionBroadcaster = new TransactionBroadcaster(Network, _bitcoinStore, _synchronizer, Nodes, _walletManager, null);
                // CoinJoinProcessor maintains an event handler to process joins.
                // We need this reference.
                _coinJoinProcessor = new CoinJoinProcessor(_synchronizer, _walletManager, null);

                #region Blocks provider

                var blockProvider = new CachedBlockProvider(
                    new SmartBlockProvider(
                        new P2pBlockProvider(Nodes, null, _synchronizer, _config.ServiceConfiguration, Network),
                        Cache),
                    new FileSystemBlockRepository(blocksFolderPath, Network));

                #endregion Blocks provider

                _walletManager.RegisterServices(_bitcoinStore, _synchronizer, Nodes, _config.ServiceConfiguration, _feeProviders, blockProvider);

                Initialized(this, new AppInitializedEventArgs(this));
                IsInitialized = true;
            }
Example #23
0
        public async Task InitializeNoWalletAsync()
        {
            InitializationStarted = true;
            AddressManager        = null;
            var cancel = StoppingCts.Token;

            try
            {
                await SingleInstanceChecker.CheckAsync().ConfigureAwait(false);

                Cache = new MemoryCache(new MemoryCacheOptions
                {
                    SizeLimit = 1_000,
                    ExpirationScanFrequency = TimeSpan.FromSeconds(30)
                });
                var bstoreInitTask           = BitcoinStore.InitializeAsync();
                var addressManagerFolderPath = Path.Combine(DataDir, "AddressManager");

                AddressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{Network}.dat");
                var addrManTask = InitializeAddressManagerBehaviorAsync();

                var userAgent            = Constants.UserAgents.RandomElement();
                var connectionParameters = new NodeConnectionParameters {
                    UserAgent = userAgent
                };

                HostedServices.Register(new UpdateChecker(TimeSpan.FromMinutes(7), Synchronizer), "Software Update Checker");

                HostedServices.Register(new SystemAwakeChecker(WalletManager), "System Awake Checker");

                #region ProcessKillSubscription

                AppDomain.CurrentDomain.ProcessExit += async(s, e) => await DisposeAsync().ConfigureAwait(false);

                Console.CancelKeyPress += async(s, e) =>
                {
                    e.Cancel = true;
                    Logger.LogWarning("Process was signaled for killing.", nameof(Global));
                    await DisposeAsync().ConfigureAwait(false);
                };

                #endregion ProcessKillSubscription

                cancel.ThrowIfCancellationRequested();

                #region TorProcessInitialization

                if (Config.UseTor)
                {
                    using (BenchmarkLogger.Measure(operationName: "TorProcessManager.Start"))
                    {
                        TorManager = new TorProcessManager(TorSettings, Config.TorSocks5EndPoint);
                        await TorManager.StartAsync(ensureRunning : true).ConfigureAwait(false);
                    }

                    var fallbackRequestTestUri = new Uri(Config.GetFallbackBackendUri(), "/api/software/versions");
                    TorManager.StartMonitor(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), fallbackRequestTestUri);
                }
                else
                {
                    TorSocks5EndPoint = null;
                }

                Logger.LogInfo($"{nameof(TorProcessManager)} is initialized.");

                #endregion TorProcessInitialization

                cancel.ThrowIfCancellationRequested();

                #region BitcoinStoreInitialization

                await bstoreInitTask.ConfigureAwait(false);

                // Make sure that the height of the wallets will not be better than the current height of the filters.
                WalletManager.SetMaxBestHeight(BitcoinStore.IndexStore.SmartHeaderChain.TipHeight);

                #endregion BitcoinStoreInitialization

                cancel.ThrowIfCancellationRequested();

                #region BitcoinCoreInitialization

                try
                {
                    if (Config.StartLocalBitcoinCoreOnStartup)
                    {
                        BitcoinCoreNode = await CoreNode
                                          .CreateAsync(
                            new CoreNodeParams(
                                Network,
                                BitcoinStore.MempoolService,
                                HostedServices,
                                Config.LocalBitcoinCoreDataDir,
                                tryRestart : false,
                                tryDeleteDataDir : false,
                                EndPointStrategy.Default(Network, EndPointType.P2p),
                                EndPointStrategy.Default(Network, EndPointType.Rpc),
                                txIndex : null,
                                prune : null,
                                mempoolReplacement : "fee,optin",
                                userAgent : $"/WasabiClient:{Constants.ClientVersion}/",
                                fallbackFee : null,                                        // ToDo: Maybe we should have it, not only for tests?
                                Cache),
                            cancel)
                                          .ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex);
                }

                await HostedServices.StartAllAsync(cancel).ConfigureAwait(false);

                var rpcFeeProvider = HostedServices.FirstOrDefault <RpcFeeProvider>();

                FeeProviders = new FeeProviders(Synchronizer, rpcFeeProvider);

                #endregion BitcoinCoreInitialization

                cancel.ThrowIfCancellationRequested();

                #region MempoolInitialization

                connectionParameters.TemplateBehaviors.Add(BitcoinStore.CreateUntrustedP2pBehavior());

                #endregion MempoolInitialization

                cancel.ThrowIfCancellationRequested();

                #region AddressManagerInitialization

                AddressManagerBehavior addressManagerBehavior = await addrManTask.ConfigureAwait(false);

                connectionParameters.TemplateBehaviors.Add(addressManagerBehavior);

                #endregion AddressManagerInitialization

                cancel.ThrowIfCancellationRequested();

                #region P2PInitialization

                if (Network == Network.RegTest)
                {
                    Nodes = new NodesGroup(Network, requirements: Constants.NodeRequirements);
                    try
                    {
                        EndPoint bitcoinCoreEndpoint = Config.GetBitcoinP2pEndPoint();

                        Node node = await Node.ConnectAsync(Network.RegTest, bitcoinCoreEndpoint).ConfigureAwait(false);

                        Nodes.ConnectedNodes.Add(node);

                        RegTestMempoolServingNode = await Node.ConnectAsync(Network.RegTest, bitcoinCoreEndpoint).ConfigureAwait(false);

                        RegTestMempoolServingNode.Behaviors.Add(BitcoinStore.CreateUntrustedP2pBehavior());
                    }
                    catch (SocketException ex)
                    {
                        Logger.LogError(ex);
                    }
                }
                else
                {
                    if (Config.UseTor)
                    {
                        // onlyForOnionHosts: false - Connect to clearnet IPs through Tor, too.
                        connectionParameters.TemplateBehaviors.Add(new SocksSettingsBehavior(Config.TorSocks5EndPoint, onlyForOnionHosts: false, networkCredential: null, streamIsolation: true));
                        // allowOnlyTorEndpoints: true - Connect only to onions and do not connect to clearnet IPs at all.
                        // This of course makes the first setting unnecessary, but it's better if that's around, in case someone wants to tinker here.
                        connectionParameters.EndpointConnector = new DefaultEndpointConnector(allowOnlyTorEndpoints: Network == Network.Main);

                        await AddKnownBitcoinFullNodeAsHiddenServiceAsync(AddressManager).ConfigureAwait(false);
                    }
                    Nodes = new NodesGroup(Network, connectionParameters, requirements: Constants.NodeRequirements);
                    Nodes.MaximumNodeConnection = 12;
                    RegTestMempoolServingNode   = null;
                }

                Nodes.Connect();
                Logger.LogInfo("Start connecting to nodes...");

                var regTestMempoolServingNode = RegTestMempoolServingNode;
                if (regTestMempoolServingNode is { })
Example #24
0
        internal void StartConnecting()
        {
            if (_Disconnect.IsCancellationRequested)
            {
                return;
            }
            if (_ConnectedNodes.Count >= MaximumNodeConnection)
            {
                return;
            }
            if (_Connecting)
            {
                return;
            }
            Task.Factory.StartNew(() =>
            {
                if (Monitor.TryEnter(cs))
                {
                    _Connecting = true;
                    TraceCorrelationScope scope = null;
                    try
                    {
                        while (!_Disconnect.IsCancellationRequested && _ConnectedNodes.Count < MaximumNodeConnection)
                        {
                            scope = scope ?? _Trace.Open();

                            NodeServerTrace.Information("Connected nodes : " + _ConnectedNodes.Count + "/" + MaximumNodeConnection);
                            var parameters = _ConnectionParameters.Clone();
                            parameters.TemplateBehaviors.Add(new NodesGroupBehavior(this));
                            parameters.ConnectCancellation = _Disconnect.Token;
                            var addrman = AddressManagerBehavior.GetAddrman(parameters);

                            if (addrman == null)
                            {
                                addrman = _DefaultAddressManager;
                                AddressManagerBehavior.SetAddrman(parameters, addrman);
                            }

                            Node node = null;
                            try
                            {
                                node        = Node.Connect(_Network, parameters, AllowSameGroup ? null : _ConnectedNodes.Select(n => n.RemoteSocketAddress).ToArray());
                                var timeout = CancellationTokenSource.CreateLinkedTokenSource(_Disconnect.Token);
                                timeout.CancelAfter(5000);
                                node.VersionHandshake(_Requirements, timeout.Token);
                                NodeServerTrace.Information("Node successfully connected to and handshaked");
                            }
                            catch (OperationCanceledException ex)
                            {
                                if (_Disconnect.Token.IsCancellationRequested)
                                {
                                    throw;
                                }
                                NodeServerTrace.Error("Timeout for picked node", ex);
                                if (node != null)
                                {
                                    node.DisconnectAsync("Handshake timeout", ex);
                                }
                            }
                            catch (Exception ex)
                            {
                                NodeServerTrace.Error("Error while connecting to node", ex);
                                if (node != null)
                                {
                                    node.DisconnectAsync("Error while connecting", ex);
                                }
                            }
                        }
                    }
                    finally
                    {
                        Monitor.Exit(cs);
                        _Connecting = false;
                        if (scope != null)
                        {
                            scope.Dispose();
                        }
                    }
                }
            }, TaskCreationOptions.LongRunning);
        }
Example #25
0
        public async Task InitializeNoWalletAsync()
        {
            try
            {
                WalletService  = null;
                ChaumianClient = null;
                AddressManager = null;
                TorManager     = null;

                #region ConfigInitialization

                Config = new Config(Path.Combine(DataDir, "Config.json"));
                await Config.LoadOrCreateDefaultFileAsync();

                Logger.LogInfo($"{nameof(Config)} is successfully initialized.");

                #endregion ConfigInitialization

                BitcoinStore = new BitcoinStore();
                var bstoreInitTask           = BitcoinStore.InitializeAsync(Path.Combine(DataDir, "BitcoinStore"), Network);
                var addressManagerFolderPath = Path.Combine(DataDir, "AddressManager");

                AddressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{Network}.dat");
                var addrManTask = InitializeAddressManagerBehaviorAsync();

                var blocksFolderPath     = Path.Combine(DataDir, $"Blocks{Network}");
                var connectionParameters = new NodeConnectionParameters {
                    UserAgent = "/Satoshi:0.18.1/"
                };

                if (Config.UseTor)
                {
                    Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, () => Config.GetCurrentBackendUri(), Config.TorSocks5EndPoint);
                }
                else
                {
                    Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, Config.GetFallbackBackendUri(), null);
                }

                HostedServices.Register(new UpdateChecker(TimeSpan.FromMinutes(7), Synchronizer.WasabiClient), "Software Update Checker");

                #region ProcessKillSubscription

                AppDomain.CurrentDomain.ProcessExit += async(s, e) => await TryDesperateDequeueAllCoinsAsync();

                Console.CancelKeyPress += async(s, e) =>
                {
                    e.Cancel = true;
                    Logger.LogWarning("Process was signaled for killing.");

                    KillRequested = true;
                    await TryDesperateDequeueAllCoinsAsync();

                    Dispatcher.UIThread.PostLogException(() =>
                    {
                        var window = (Application.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).MainWindow;
                        window?.Close();
                    });
                    await DisposeAsync();

                    Logger.LogSoftwareStopped("Wasabi");
                };

                #endregion ProcessKillSubscription

                #region TorProcessInitialization

                if (Config.UseTor)
                {
                    TorManager = new TorProcessManager(Config.TorSocks5EndPoint, TorLogsFile);
                }
                else
                {
                    TorManager = TorProcessManager.Mock();
                }
                TorManager.Start(false, DataDir);

                var fallbackRequestTestUri = new Uri(Config.GetFallbackBackendUri(), "/api/software/versions");
                TorManager.StartMonitor(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), DataDir, fallbackRequestTestUri);

                Logger.LogInfo($"{nameof(TorProcessManager)} is initialized.");

                #endregion TorProcessInitialization

                #region BitcoinStoreInitialization

                await bstoreInitTask;

                #endregion BitcoinStoreInitialization

                #region BitcoinCoreInitialization

                try
                {
                    if (Config.StartLocalBitcoinCoreOnStartup)
                    {
                        BitcoinCoreNode = await CoreNode
                                          .CreateAsync(
                            new CoreNodeParams(
                                Network,
                                BitcoinStore.MempoolService,
                                HostedServices,
                                Config.LocalBitcoinCoreDataDir,
                                tryRestart : false,
                                tryDeleteDataDir : false,
                                EndPointStrategy.Default(Network, EndPointType.P2p),
                                EndPointStrategy.Default(Network, EndPointType.Rpc),
                                txIndex : null,
                                prune : null,
                                userAgent : $"/WasabiClient:{Constants.ClientVersion.ToString()}/"),
                            CancellationToken.None)
                                          .ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex);
                }

                await HostedServices.StartAllAsync(StoppingCts.Token).ConfigureAwait(false);

                var feeProviderList = new List <IFeeProvider>
                {
                    Synchronizer
                };

                var rpcFeeProvider = HostedServices.FirstOrDefault <RpcFeeProvider>();
                if (rpcFeeProvider is { })
                {
                    feeProviderList.Insert(0, rpcFeeProvider);
                }

                FeeProviders = new FeeProviders(feeProviderList);

                #endregion BitcoinCoreInitialization

                #region MempoolInitialization

                connectionParameters.TemplateBehaviors.Add(BitcoinStore.CreateUntrustedP2pBehavior());

                #endregion MempoolInitialization

                #region AddressManagerInitialization

                AddressManagerBehavior addressManagerBehavior = await addrManTask;
                connectionParameters.TemplateBehaviors.Add(addressManagerBehavior);

                #endregion AddressManagerInitialization

                #region P2PInitialization

                if (Network == Network.RegTest)
                {
                    Nodes = new NodesGroup(Network, requirements: Constants.NodeRequirements);
                    try
                    {
                        EndPoint bitcoinCoreEndpoint = Config.GetBitcoinP2pEndPoint();

                        Node node = await Node.ConnectAsync(Network.RegTest, bitcoinCoreEndpoint).ConfigureAwait(false);

                        Nodes.ConnectedNodes.Add(node);

                        RegTestMempoolServingNode = await Node.ConnectAsync(Network.RegTest, bitcoinCoreEndpoint).ConfigureAwait(false);

                        RegTestMempoolServingNode.Behaviors.Add(BitcoinStore.CreateUntrustedP2pBehavior());
                    }
                    catch (SocketException ex)
                    {
                        Logger.LogError(ex);
                    }
                }
                else
                {
                    if (Config.UseTor is true)
                    {
                        // onlyForOnionHosts: false - Connect to clearnet IPs through Tor, too.
                        connectionParameters.TemplateBehaviors.Add(new SocksSettingsBehavior(Config.TorSocks5EndPoint, onlyForOnionHosts: false, networkCredential: null, streamIsolation: true));
                        // allowOnlyTorEndpoints: true - Connect only to onions and do not connect to clearnet IPs at all.
                        // This of course makes the first setting unnecessary, but it's better if that's around, in case someone wants to tinker here.
                        connectionParameters.EndpointConnector = new DefaultEndpointConnector(allowOnlyTorEndpoints: Network == Network.Main);

                        await AddKnownBitcoinFullNodeAsHiddenServiceAsync(AddressManager);
                    }
                    Nodes = new NodesGroup(Network, connectionParameters, requirements: Constants.NodeRequirements);

                    RegTestMempoolServingNode = null;
                }

                Nodes.Connect();
                Logger.LogInfo("Start connecting to nodes...");

                var regTestMempoolServingNode = RegTestMempoolServingNode;
                if (regTestMempoolServingNode is { })
Example #26
0
        public void CanSyncWalletCore(WalletCreation creation)
        {
            using (NodeServerTester servers = new NodeServerTester(Network.TestNet))
            {
                var chainBuilder = new BlockchainBuilder();

                //Simulate SPV compatible server
                servers.Server1.InboundNodeConnectionParameters.Services = NodeServices.Network;
                servers.Server1.InboundNodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(chainBuilder.Chain)
                {
                    AutoSync = false
                });
                servers.Server1.InboundNodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(chainBuilder));
                /////////////

                //The SPV client does not verify the chain and keep one connection alive with Server1
                NodeConnectionParameters parameters = new NodeConnectionParameters();
                Wallet.ConfigureDefaultNodeConnectionParameters(parameters);
                parameters.IsTrusted = true;
                AddressManagerBehavior addrman = new AddressManagerBehavior(new AddressManager());
                addrman.AddressManager.Add(new NetworkAddress(servers.Server1.ExternalEndpoint), IPAddress.Parse("127.0.0.1"));
                parameters.TemplateBehaviors.Add(addrman);
                NodesGroup connected = new NodesGroup(Network.TestNet, parameters);
                connected.AllowSameGroup        = true;
                connected.MaximumNodeConnection = 1;
                /////////////

                Wallet wallet = new Wallet(creation, keyPoolSize: 11);
                Assert.True(wallet.State == WalletState.Created);
                wallet.Connect(connected);
                Assert.True(wallet.State == WalletState.Disconnected);
                TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1);
                Assert.True(wallet.State == WalletState.Connected);

                chainBuilder.FindBlock();
                TestUtils.Eventually(() => wallet.Chain.Height == 1);
                for (int i = 0; i < 9; i++)
                {
                    wallet.GetNextScriptPubKey();
                }
                wallet.GetNextScriptPubKey();                 //Should provoke purge
                TestUtils.Eventually(() => wallet.State == WalletState.Disconnected && wallet.ConnectedNodes == 0);
                TestUtils.Eventually(() => wallet.ConnectedNodes == 1);
                TestUtils.Eventually(() => servers.Server1.ConnectedNodes.Count == 1);
                var spv = servers.Server1.ConnectedNodes.First().Behaviors.Find <SPVBehavior>();
                TestUtils.Eventually(() => spv._Filter != null);

                var k = wallet.GetNextScriptPubKey();
                Assert.Equal(creation.UseP2SH, k.GetDestinationAddress(Network.TestNet) is BitcoinScriptAddress);
                chainBuilder.GiveMoney(k, Money.Coins(1.0m));
                TestUtils.Eventually(() => wallet.GetTransactions().Count == 1);
                chainBuilder.FindBlock();
                TestUtils.Eventually(() => wallet.GetTransactions().Where(t => t.BlockInformation != null).Count() == 1);

                chainBuilder.Broadcast = false;
                chainBuilder.GiveMoney(k, Money.Coins(1.5m));
                chainBuilder.Broadcast = true;
                chainBuilder.FindBlock();
                TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 2);

                chainBuilder.Broadcast = false;
                for (int i = 0; i < 30; i++)
                {
                    chainBuilder.FindBlock();
                }
                chainBuilder.GiveMoney(k, Money.Coins(0.001m));
                chainBuilder.FindBlock();
                chainBuilder.Broadcast = true;
                chainBuilder.FindBlock();
                //Sync automatically
                TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 3);

                MemoryStream ms = new MemoryStream();
                wallet.Save(ms);
                ms.Position = 0;
                var wallet2 = Wallet.Load(ms);
                wallet2.Connect(connected);
                Assert.Equal(wallet.Created, wallet2.Created);
                Assert.Equal(wallet.GetNextScriptPubKey(), wallet2.GetNextScriptPubKey());
                Assert.True(wallet.GetKnownScripts().Length == wallet2.GetKnownScripts().Length);

                var fork = wallet.Chain.FindFork(wallet2._ScanLocation);
                Assert.True(fork.Height == chainBuilder.Chain.Height - 5);
            }
        }
Example #27
0
        public static async Task InitializeNoWalletAsync()
        {
            WalletService  = null;
            ChaumianClient = null;
            AddressManager = null;
            TorManager     = null;

            #region ConfigInitialization

            Config = new Config(Path.Combine(DataDir, "Config.json"));
            await Config.LoadOrCreateDefaultFileAsync();

            Logger.LogInfo <Config>("Config is successfully initialized.");

            #endregion ConfigInitialization

            BitcoinStore = new BitcoinStore();
            var bstoreInitTask = BitcoinStore.InitializeAsync(Path.Combine(DataDir, "BitcoinStore"), Network);
            var hwiInitTask    = HwiProcessManager.InitializeAsync(DataDir, Network);

            var addressManagerFolderPath = Path.Combine(DataDir, "AddressManager");
            AddressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{Network}.dat");
            var blocksFolderPath     = Path.Combine(DataDir, $"Blocks{Network}");
            var connectionParameters = new NodeConnectionParameters();

            if (Config.UseTor.Value)
            {
                Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, () => Config.GetCurrentBackendUri(), Config.GetTorSocks5EndPoint());
            }
            else
            {
                Synchronizer = new WasabiSynchronizer(Network, BitcoinStore, Config.GetFallbackBackendUri(), null);
            }

            UpdateChecker = new UpdateChecker(Synchronizer.WasabiClient);

            #region ProcessKillSubscription

            AppDomain.CurrentDomain.ProcessExit += async(s, e) => await TryDesperateDequeueAllCoinsAsync();

            Console.CancelKeyPress += async(s, e) =>
            {
                e.Cancel = true;
                Logger.LogWarning("Process was signaled for killing.", nameof(Global));

                KillRequested = true;
                await TryDesperateDequeueAllCoinsAsync();

                Dispatcher.UIThread.PostLogException(() =>
                {
                    Application.Current?.MainWindow?.Close();
                });
            };

            #endregion ProcessKillSubscription

            #region TorProcessInitialization

            if (Config.UseTor.Value)
            {
                TorManager = new TorProcessManager(Config.GetTorSocks5EndPoint(), TorLogsFile);
            }
            else
            {
                TorManager = TorProcessManager.Mock();
            }
            TorManager.Start(false, DataDir);

            var fallbackRequestTestUri = new Uri(Config.GetFallbackBackendUri(), "/api/software/versions");
            TorManager.StartMonitor(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(7), DataDir, fallbackRequestTestUri);

            Logger.LogInfo <TorProcessManager>($"{nameof(TorProcessManager)} is initialized.");

            #endregion TorProcessInitialization

            #region AddressManagerInitialization

            var needsToDiscoverPeers = true;
            if (Network == Network.RegTest)
            {
                AddressManager = new AddressManager();
                Logger.LogInfo <AddressManager>($"Fake {nameof(AddressManager)} is initialized on the RegTest.");
            }
            else
            {
                try
                {
                    AddressManager = AddressManager.LoadPeerFile(AddressManagerFilePath);

                    // The most of the times we don't need to discover new peers. Instead, we can connect to
                    // some of those that we already discovered in the past. In this case we assume that we
                    // assume that discovering new peers could be necessary if out address manager has less
                    // than 500 addresses. A 500 addresses could be okay because previously we tried with
                    // 200 and only one user reported he/she was not able to connect (there could be many others,
                    // of course).
                    // On the other side, increasing this number forces users that do not need to discover more peers
                    // to spend resources (CPU/bandwith) to discover new peers.
                    needsToDiscoverPeers = Config.UseTor == true || AddressManager.Count < 500;
                    Logger.LogInfo <AddressManager>($"Loaded {nameof(AddressManager)} from `{AddressManagerFilePath}`.");
                }
                catch (DirectoryNotFoundException ex)
                {
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one.");
                    Logger.LogTrace <AddressManager>(ex);
                    AddressManager = new AddressManager();
                }
                catch (FileNotFoundException ex)
                {
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} did not exist at `{AddressManagerFilePath}`. Initializing new one.");
                    Logger.LogTrace <AddressManager>(ex);
                    AddressManager = new AddressManager();
                }
                catch (OverflowException ex)
                {
                    // https://github.com/zkSNACKs/WalletWasabi/issues/712
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} has thrown `{nameof(OverflowException)}`. Attempting to autocorrect.");
                    File.Delete(AddressManagerFilePath);
                    Logger.LogTrace <AddressManager>(ex);
                    AddressManager = new AddressManager();
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} autocorrection is successful.");
                }
                catch (FormatException ex)
                {
                    // https://github.com/zkSNACKs/WalletWasabi/issues/880
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} has thrown `{nameof(FormatException)}`. Attempting to autocorrect.");
                    File.Delete(AddressManagerFilePath);
                    Logger.LogTrace <AddressManager>(ex);
                    AddressManager = new AddressManager();
                    Logger.LogInfo <AddressManager>($"{nameof(AddressManager)} autocorrection is successful.");
                }
            }

            var addressManagerBehavior = new AddressManagerBehavior(AddressManager)
            {
                Mode = needsToDiscoverPeers ? AddressManagerBehaviorMode.Discover : AddressManagerBehaviorMode.None
            };
            connectionParameters.TemplateBehaviors.Add(addressManagerBehavior);

            #endregion AddressManagerInitialization

            #region MempoolInitialization

            MemPoolService = new MemPoolService();
            connectionParameters.TemplateBehaviors.Add(new MemPoolBehavior(MemPoolService));

            #endregion MempoolInitialization

            #region HwiProcessInitialization

            try
            {
                await hwiInitTask;
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, nameof(Global));
            }

            #endregion HwiProcessInitialization

            #region BitcoinStoreInitialization

            await bstoreInitTask;

            #endregion BitcoinStoreInitialization

            #region P2PInitialization

            if (Network == Network.RegTest)
            {
                Nodes = new NodesGroup(Network, requirements: Constants.NodeRequirements);
                try
                {
                    Node node = await Node.ConnectAsync(Network.RegTest, new IPEndPoint(IPAddress.Loopback, 18444));

                    Nodes.ConnectedNodes.Add(node);

                    RegTestMemPoolServingNode = await Node.ConnectAsync(Network.RegTest, new IPEndPoint(IPAddress.Loopback, 18444));

                    RegTestMemPoolServingNode.Behaviors.Add(new MemPoolBehavior(MemPoolService));
                }
                catch (SocketException ex)
                {
                    Logger.LogError(ex, nameof(Global));
                }
            }
            else
            {
                if (Config.UseTor is true)
                {
                    // onlyForOnionHosts: false - Connect to clearnet IPs through Tor, too.
                    connectionParameters.TemplateBehaviors.Add(new SocksSettingsBehavior(Config.GetTorSocks5EndPoint(), onlyForOnionHosts: false, networkCredential: null, streamIsolation: true));
                    // allowOnlyTorEndpoints: true - Connect only to onions and don't connect to clearnet IPs at all.
                    // This of course makes the first setting unneccessary, but it's better if that's around, in case someone wants to tinker here.
                    connectionParameters.EndpointConnector = new DefaultEndpointConnector(allowOnlyTorEndpoints: Network == Network.Main);

                    await AddKnownBitcoinFullNodeAsHiddenServiceAsync(AddressManager);
                }
                Nodes = new NodesGroup(Network, connectionParameters, requirements: Constants.NodeRequirements);

                RegTestMemPoolServingNode = null;
            }

            Nodes.Connect();
            Logger.LogInfo("Start connecting to nodes...");

            if (RegTestMemPoolServingNode != null)
            {
                RegTestMemPoolServingNode.VersionHandshake();
                Logger.LogInfo("Start connecting to mempool serving regtest node...");
            }

            #endregion P2PInitialization

            #region SynchronizerInitialization

            var requestInterval = TimeSpan.FromSeconds(30);
            if (Network == Network.RegTest)
            {
                requestInterval = TimeSpan.FromSeconds(5);
            }

            int maxFiltSyncCount = Network == Network.Main ? 1000 : 10000;             // On testnet, filters are empty, so it's faster to query them together

            Synchronizer.Start(requestInterval, TimeSpan.FromMinutes(5), maxFiltSyncCount);
            Logger.LogInfo("Start synchronizing filters...");

            #endregion SynchronizerInitialization

            Initialized = true;
        }
Example #28
0
 protected bool AddressManagerContains(NodeServer nodeServer, IPEndPoint ipEndPoint)
 {
     return(AddressManagerContains(AddressManagerBehavior.GetAddrman(nodeServer.InboundNodeConnectionParameters.TemplateBehaviors), ipEndPoint));
 }
Example #29
0
        /// <summary>
        /// Configure the components of the wallet
        /// </summary>
        /// <param name="group">The group to use</param>
        public void Configure(NodesGroup group)
        {
            if (group == null)
            {
                throw new ArgumentNullException(nameof(group));
            }

            var parameters = group.NodeConnectionParameters;

            group.Requirements.SupportSPV = true;

            var chain = parameters.TemplateBehaviors.Find <ChainBehavior>();

            if (chain == null)
            {
                chain = new ChainBehavior(new ConcurrentChain(_Parameters.Network));
                parameters.TemplateBehaviors.Add(chain);
            }
            if (chain.Chain.Genesis.HashBlock != _Parameters.Network.GetGenesis().GetHash())
            {
                throw new InvalidOperationException("ChainBehavior with invalid network chain detected");
            }

            var addrman = parameters.TemplateBehaviors.Find <AddressManagerBehavior>();

            if (addrman == null)
            {
                addrman = new AddressManagerBehavior(new AddressManager());
                parameters.TemplateBehaviors.Add(addrman);
            }

#pragma warning disable CS0612 // Type or member is obsolete
            var tracker = parameters.TemplateBehaviors.Find <TrackerBehavior>();
#pragma warning restore CS0612 // Type or member is obsolete
            if (tracker == null)
            {
#pragma warning disable CS0612 // Type or member is obsolete
#pragma warning disable CS0612 // Type or member is obsolete
                tracker = new TrackerBehavior(new Tracker(), chain.Chain);
#pragma warning restore CS0612 // Type or member is obsolete
#pragma warning restore CS0612 // Type or member is obsolete
                parameters.TemplateBehaviors.Add(tracker);
            }
            var wallet = FindWalletBehavior(parameters.TemplateBehaviors);
            if (wallet == null)
            {
                wallet = new WalletBehavior(this);
                parameters.TemplateBehaviors.Add(wallet);
            }
            var broadcast = parameters.TemplateBehaviors.Find <BroadcastHubBehavior>();
            if (broadcast == null)
            {
                broadcast = new BroadcastHubBehavior();
                parameters.TemplateBehaviors.Add(broadcast);
            }

            _Group = group;
            if (_ListenedTracker != null)
            {
                _ListenedTracker.NewOperation -= _ListenerTracked_NewOperation;
            }
            _ListenedTracker = tracker.Tracker;
            _ListenedTracker.NewOperation += _ListenerTracked_NewOperation;
        }
Example #30
0
        public void Start()
        {
            this.logger.LogTrace("()");

            this.parameters.UserAgent = $"{this.NodeSettings.Agent}:{this.GetVersion()}";
            this.parameters.Version   = this.NodeSettings.ProtocolVersion;

            if (this.connectionManagerSettings.Connect.Count == 0)
            {
                NodeConnectionParameters cloneParameters = this.parameters.Clone();
                cloneParameters.TemplateBehaviors.Add(new ConnectionManagerBehavior(false, this, this.loggerFactory));
                this.DiscoveredNodeGroup = CreateNodeGroup(cloneParameters, this.discoveredNodeRequiredService);
                this.DiscoveredNodeGroup.CustomGroupSelector = WellKnownGroupSelectors.ByNetwork; // It is the default, but I want to use it.
            }
            else
            {
                NodeConnectionParameters cloneParameters = this.parameters.Clone();
                cloneParameters.TemplateBehaviors.Add(new ConnectionManagerBehavior(false, this, this.loggerFactory));
                cloneParameters.TemplateBehaviors.Remove <AddressManagerBehavior>();

                var addrman = new AddressManager();
                addrman.Add(this.connectionManagerSettings.Connect.Select(c => new NetworkAddress(c)).ToArray(), IPAddress.Loopback);

                var addrmanBehavior = new AddressManagerBehavior(addrman)
                {
                    PeersToDiscover = 10
                };
                addrmanBehavior.Mode = AddressManagerBehaviorMode.None;
                cloneParameters.TemplateBehaviors.Add(addrmanBehavior);

                this.ConnectNodeGroup = CreateNodeGroup(cloneParameters, NodeServices.Nothing);
                this.ConnectNodeGroup.MaximumNodeConnection = this.connectionManagerSettings.Connect.Count;
                this.ConnectNodeGroup.CustomGroupSelector   = WellKnownGroupSelectors.ByEndpoint;
            }

            {
                NodeConnectionParameters cloneParameters = this.parameters.Clone();
                cloneParameters.TemplateBehaviors.Add(new ConnectionManagerBehavior(false, this, this.loggerFactory));
                cloneParameters.TemplateBehaviors.Remove <AddressManagerBehavior>();
                var addrman = new AddressManager();
                addrman.Add(this.connectionManagerSettings.AddNode.Select(c => new NetworkAddress(c)).ToArray(), IPAddress.Loopback);
                var addrmanBehavior = new AddressManagerBehavior(addrman)
                {
                    PeersToDiscover = 10
                };
                addrmanBehavior.Mode = AddressManagerBehaviorMode.AdvertizeDiscover;
                cloneParameters.TemplateBehaviors.Add(addrmanBehavior);

                this.AddNodeNodeGroup = CreateNodeGroup(cloneParameters, NodeServices.Nothing);
                this.AddNodeNodeGroup.MaximumNodeConnection = this.connectionManagerSettings.AddNode.Count;
                this.AddNodeNodeGroup.CustomGroupSelector   = WellKnownGroupSelectors.ByEndpoint;
            }

            // Related the groups to each other to prevent duplicate connections.
            RelatedNodesGroups relGroups = new RelatedNodesGroups();

            relGroups.Register("Discovered", this.DiscoveredNodeGroup);
            relGroups.Register("Connect", this.ConnectNodeGroup);
            relGroups.Register("AddNode", this.AddNodeNodeGroup);
            this.DiscoveredNodeGroup?.Connect();
            this.ConnectNodeGroup?.Connect();
            this.AddNodeNodeGroup?.Connect();

            StringBuilder logs = new StringBuilder();

            logs.AppendLine("Node listening on:");
            foreach (NodeServerEndpoint listen in this.connectionManagerSettings.Listen)
            {
                NodeConnectionParameters cloneParameters = this.parameters.Clone();
                var server = new NodeServer(this.Network)
                {
                    LocalEndpoint    = listen.Endpoint,
                    ExternalEndpoint = this.connectionManagerSettings.ExternalEndpoint
                };

                this.Servers.Add(server);
                cloneParameters.TemplateBehaviors.Add(new ConnectionManagerBehavior(true, this, this.loggerFactory)
                {
                    Whitelisted = listen.Whitelisted
                });

                server.InboundNodeConnectionParameters = cloneParameters;
                server.Listen();

                logs.Append(listen.Endpoint.Address + ":" + listen.Endpoint.Port);
                if (listen.Whitelisted)
                {
                    logs.Append(" (whitelisted)");
                }
                logs.AppendLine();
            }
            this.logger.LogInformation(logs.ToString());

            this.logger.LogTrace("(-)");
        }