protected override void Dispose(bool disposing) { if (_disposed) { return; } if (disposing) { if (components != null) { components.Dispose(); } if (_group != null) { _group.Disconnect(); _group.Dispose(); } } base.Dispose(disposing); _disposed = true; }
private void StopNodeGroup() { if (_group != null) { _group.Dispose(); } _group = null; }
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(); }
public async Task TestServicesAsync(string networkString) { var network = Network.GetNetwork(networkString); var blocksToDownload = new HashSet <uint256>(); if (network == Network.Main) { blocksToDownload.Add(new uint256("00000000000000000037c2de35bd85f3e57f14ddd741ce6cee5b28e51473d5d0")); blocksToDownload.Add(new uint256("000000000000000000115315a43cb0cdfc4ea54a0e92bed127f4e395e718d8f9")); blocksToDownload.Add(new uint256("00000000000000000011b5b042ad0522b69aae36f7de796f563c895714bbd629")); } else if (network == Network.TestNet) { blocksToDownload.Add(new uint256("0000000097a664c4084b49faa6fd4417055cb8e5aac480abc31ddc57a8208524")); blocksToDownload.Add(new uint256("000000009ed5b82259ecd2aa4cd1f119db8da7a70e7ea78d9c9f603e01f93bcc")); blocksToDownload.Add(new uint256("00000000e6da8c2da304e9f5ad99c079df2c3803b49efded3061ecaf206ddc66")); } else { throw new NotSupportedException(network.ToString()); } var addressManagerFolderPath = Path.Combine(Global.Instance.DataDir, "AddressManager"); var addressManagerFilePath = Path.Combine(addressManagerFolderPath, $"AddressManager{network}.dat"); var blocksFolderPath = Path.Combine(Global.Instance.DataDir, "Blocks", network.ToString()); var connectionParameters = new NodeConnectionParameters(); AddressManager addressManager = null; try { addressManager = AddressManager.LoadPeerFile(addressManagerFilePath); 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(); } connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager)); var memPoolService = new MemPoolService(); connectionParameters.TemplateBehaviors.Add(new MemPoolBehavior(memPoolService)); var nodes = new NodesGroup(network, connectionParameters, requirements: Helpers.Constants.NodeRequirements); BitcoinStore bitcoinStore = new BitcoinStore(); await bitcoinStore.InitializeAsync(Path.Combine(Global.Instance.DataDir, nameof(TestServicesAsync)), network); KeyManager keyManager = KeyManager.CreateNew(out _, "password"); WasabiSynchronizer syncer = new WasabiSynchronizer(network, bitcoinStore, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint); WalletService walletService = new WalletService( bitcoinStore, keyManager, syncer, new CcjClient(syncer, network, keyManager, new Uri("http://localhost:12345"), Global.Instance.TorSocks5Endpoint), memPoolService, nodes, Global.Instance.DataDir, new ServiceConfiguration(50, 2, 21, 50, new IPEndPoint(IPAddress.Loopback, network.DefaultPort), Money.Coins(0.0001m))); Assert.True(Directory.Exists(blocksFolderPath)); try { nodes.ConnectedNodes.Added += ConnectedNodes_Added; nodes.ConnectedNodes.Removed += ConnectedNodes_Removed; memPoolService.TransactionReceived += MemPoolService_TransactionReceived; nodes.Connect(); // Using the interlocked, not because it makes sense in this context, but to // set an example that these values are often concurrency sensitive var times = 0; while (Interlocked.Read(ref _nodeCount) < 3) { if (times > 4200) // 7 minutes { throw new TimeoutException($"Connection test timed out."); } await Task.Delay(100); times++; } times = 0; while (Interlocked.Read(ref _mempoolTransactionCount) < 3) { if (times > 3000) // 3 minutes { throw new TimeoutException($"{nameof(MemPoolService)} test timed out."); } await Task.Delay(100); times++; } foreach (var hash in blocksToDownload) { using (var cts = new CancellationTokenSource(TimeSpan.FromMinutes(3))) { var block = await walletService.GetOrDownloadBlockAsync(hash, cts.Token); Assert.True(File.Exists(Path.Combine(blocksFolderPath, hash.ToString()))); Logger.LogInfo <P2pTests>($"Full block is downloaded: {hash}."); } } } finally { nodes.ConnectedNodes.Added -= ConnectedNodes_Added; nodes.ConnectedNodes.Removed -= ConnectedNodes_Removed; memPoolService.TransactionReceived -= MemPoolService_TransactionReceived; // So next test will download the block. foreach (var hash in blocksToDownload) { await walletService?.DeleteBlockAsync(hash); } if (walletService != null) { await walletService.StopAsync(); } if (Directory.Exists(blocksFolderPath)) { Directory.Delete(blocksFolderPath, recursive: true); } IoHelpers.EnsureContainingDirectoryExists(addressManagerFilePath); addressManager?.SavePeerFile(addressManagerFilePath, network); Logger.LogInfo <P2pTests>($"Saved {nameof(AddressManager)} to `{addressManagerFilePath}`."); nodes?.Dispose(); await syncer?.StopAsync(); } }
static void Main(string[] args) { var connectionParameters = new NodeConnectionParameters() { ReceiveBufferSize = 1048576, SendBufferSize = 1048576 }; var addressManagerFilePath = "AddressManager.dat"; AddressManager addressManager; try { addressManager = AddressManager.LoadPeerFile(addressManagerFilePath); Console.WriteLine($"Loaded {nameof(AddressManager)} from `{addressManagerFilePath}`."); } catch (FileNotFoundException) { Console.WriteLine($"{nameof(AddressManager)} did not exist at `{addressManagerFilePath}`. Initializing new one."); addressManager = new AddressManager(); } connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(addressManager)); var nodes = new NodesGroup(Network.Main, connectionParameters, new NodeRequirement { RequiredServices = NodeServices.Network, MinVersion = ProtocolVersion.WITNESS_VERSION }); Console.WriteLine("Start connecting to nodes..."); nodes.Connect(); Console.WriteLine(); Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.AddressFrom)}: {connectionParameters.AddressFrom}"); Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.IsRelay)}: {connectionParameters.IsRelay}"); Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.PreferredTransactionOptions)}: {connectionParameters.PreferredTransactionOptions}"); Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.ReceiveBufferSize)}: {connectionParameters.ReceiveBufferSize}"); Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.ReuseBuffer)}: {connectionParameters.ReuseBuffer}"); Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.SendBufferSize)}: {connectionParameters.SendBufferSize}"); Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.Services)}: {connectionParameters.Services}"); Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.TemplateBehaviors)}.Count(): {connectionParameters.TemplateBehaviors.Count()}"); Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.UserAgent)}: {connectionParameters.UserAgent}"); Console.WriteLine($"{nameof(connectionParameters)}.{nameof(connectionParameters.Version)}: {connectionParameters.Version}"); Console.WriteLine(); Console.WriteLine($"{nameof(addressManager)}.{nameof(addressManager.Count)}: {addressManager.Count}"); Console.WriteLine($"{nameof(addressManager)}.GetAddr().Count(): {addressManager.GetAddr().Count()}"); Console.WriteLine($"{nameof(addressManager)}.GetSerializedSize(): {addressManager.GetSerializedSize()}"); Console.WriteLine(); Console.WriteLine($"{nameof(nodes)}.{nameof(nodes.AllowSameGroup)}: {nodes.AllowSameGroup}"); Console.WriteLine($"{nameof(nodes)}.{nameof(nodes.ConnectedNodes)}.{nameof(nodes.ConnectedNodes.Count)}: {nodes.ConnectedNodes.Count}"); Console.WriteLine($"{nameof(nodes)}.{nameof(nodes.MaximumNodeConnection)}: {nodes.MaximumNodeConnection}"); Console.WriteLine($"{nameof(nodes)}.{nameof(nodes.Requirements)}.{nameof(nodes.Requirements.MinVersion)}: {nodes.Requirements.MinVersion}"); Console.WriteLine($"{nameof(nodes)}.{nameof(nodes.Requirements)}.{nameof(nodes.Requirements.RequiredServices)}: {nodes.Requirements.RequiredServices}"); Console.WriteLine($"{nameof(nodes)}.{nameof(nodes.Requirements)}.{nameof(nodes.Requirements.SupportSPV)}: {nodes.Requirements.SupportSPV}"); Console.WriteLine(); try { int i = 0; while (i < 42) // 7 minutes { Console.WriteLine($"Witing for a connection for {i / (double)6} minutes...."); if (nodes.ConnectedNodes.Count >= 1) { Console.WriteLine("SUCCESSFULLY FOUND A CONNECTION"); return; } Task.Delay(TimeSpan.FromSeconds(10)).GetAwaiter().GetResult(); i++; } throw new TimeoutException($"DID NOT FIND A CONNECTION within {i / (double)6} minutes."); } finally { Console.WriteLine($"Saving {nameof(AddressManager)} to `{addressManagerFilePath}`."); addressManager.SavePeerFile(addressManagerFilePath, Network.Main); nodes.Dispose(); } }
public static void Main(string[] args) { Directory.CreateDirectory(SpvFolderPath); // TestNet addresses, first time used //var a1 = BitcoinAddress.Create("2Mz3BiReit6sNrSh9EMuhwUnhtqf2B35HpN"); // testnet, 1088037 //var a2 = BitcoinAddress.Create("mwiSUHLGngZd849Sz3TE6kRb7fHjJCuwKe"); // testnet, 1088031 //var a3 = BitcoinAddress.Create("muE3Z5Lhdk3WerqVevH49htmV96HJu4RLJ"); // testnet, 1088031 //LocalPartialChain.Track(a1.ScriptPubKey); //LocalPartialChain.Track(a2.ScriptPubKey); //LocalPartialChain.Track(a3.ScriptPubKey); //Console.WriteLine($"Tracking {a1}"); //Console.WriteLine($"Tracking {a2}"); //Console.WriteLine($"Tracking {a3}"); _connectionParameters = new NodeConnectionParameters(); //So we find nodes faster _connectionParameters.TemplateBehaviors.Add(new AddressManagerBehavior(AddressManager)); //So we don't have to load the chain each time we start _connectionParameters.TemplateBehaviors.Add(new ChainBehavior(LocalSpvChain)); _nodes = new NodesGroup(Network, _connectionParameters, new NodeRequirement { RequiredServices = NodeServices.Network, MinVersion = ProtocolVersion.SENDHEADERS_VERSION }); var bp = new NodesBlockPuller(LocalSpvChain, _nodes.ConnectedNodes); _connectionParameters.TemplateBehaviors.Add(new NodesBlockPuller.NodesBlockPullerBehavior(bp)); _nodes.NodeConnectionParameters = _connectionParameters; BlockPuller = (LookaheadBlockPuller)bp; MemPoolJob memPool = new MemPoolJob(_nodes, LocalPartialChain); Console.WriteLine("Start connecting to nodes..."); _nodes.Connect(); CancellationTokenSource cts = new CancellationTokenSource(); var t1 = ReportConnectedNodeCountAsync(cts.Token); var t2 = ReportHeightAsync(cts.Token); var t3 = PeriodicSaveAsync(TimeSpan.FromMinutes(3), cts.Token); var t4 = BlockPullerJobAsync(cts.Token); //var t5 = ReportTransactionsWhenAllBlocksDownAsync(cts.Token); var t6 = memPool.StartAsync(cts.Token); var t7 = ReportMemPoolStateAsync(memPool, cts.Token); //ReportTransactions(); Console.WriteLine("Press a key to exit..."); Console.ReadKey(); Console.WriteLine("Exiting..."); cts.Cancel(); Task.WhenAll(t1, t2, t3, t4, t6, t7).Wait(); //, t5, t6).Wait(); SaveAllAsync().Wait(); _nodes.Dispose(); }
private void Dump(DumpOptions o) { if (o.Address == null) { throw new FormatException(); } var destination = BitcoinAddress.Create(o.Address); if (destination is BitcoinWitScriptAddress || destination is BitcoinWitPubKeyAddress) { throw new FormatException("BCC disabled segwit, segwit address unsupported"); } UTXO[] utxos = GetDumpingUTXOs(); if (utxos.Length == 0) { Logs.Main.LogWarning("No UTXO selected to dump, use `select` command to select UTXOs to select for dump"); return; } Logs.Main.LogInformation("Dumping " + utxos.Length + " UTXOs"); 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; } } var total = utxos.Select(u => u.Amount).Sum(); var fee = Money.Zero; var coins = utxos.Select(u => u.AsCoin()); 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(FetchKeys(coins).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()); 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() + ", when this transaction is confirmed, unlock your Bitcoins again with `confirm " + dumpTransaction.GetHash() + "`"); group.Disconnect(); group.Dispose(); }; group.Connect(); }