Пример #1
0
        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;
        }
Пример #2
0
 private void StopNodeGroup()
 {
     if (_group != null)
     {
         _group.Dispose();
     }
     _group = null;
 }
Пример #3
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();
        }
Пример #4
0
        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();
            }
        }
Пример #5
0
        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();
            }
        }
Пример #6
0
        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();
        }
Пример #7
0
        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();
        }