public void AddNodeAddress(IPEndPoint endpoint) { AddressManager addrman = AddressManagerBehavior.GetAddrman(this.AddNodeNodeGroup.NodeConnectionParameters); addrman.Add(new NetworkAddress(endpoint)); this.AddNodeNodeGroup.MaximumNodeConnection++; }
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); } }
/// <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); } } }
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");
public NodeManager(BlockChain.BlockChain blockChain) { _BlockChain = blockChain; var addressManager = new AddressManager(); _NodeConnectionParameters = new NodeConnectionParameters(); var addressManagerBehavior = new AddressManagerBehavior(addressManager); _NodeConnectionParameters.TemplateBehaviors.Add(addressManagerBehavior); }
/// <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; }
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("(-)"); }
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); }
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); }
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}"); }
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); }
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}"); }
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); }
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()); } }
protected bool AddressManagerContains(Node node, IPEndPoint ipEndPoint) { return(AddressManagerContains(AddressManagerBehavior.GetAddrman(node), ipEndPoint)); }
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(); }
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()); }
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..."); }
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; }
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; } }
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; }
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 { })
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); }
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 { })
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); } }
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; }
protected bool AddressManagerContains(NodeServer nodeServer, IPEndPoint ipEndPoint) { return(AddressManagerContains(AddressManagerBehavior.GetAddrman(nodeServer.InboundNodeConnectionParameters.TemplateBehaviors), ipEndPoint)); }
/// <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; }
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("(-)"); }