示例#1
0
        /// <inheritdoc />
        public async Task <ClassicTumblerParameters> ConnectToTumblerAsync(Uri serverAddress)
        {
            // TODO this method will probably need to change as the connection to a tumbler is currently done during configuration
            // of the TumblebitRuntime. This method can then be modified to potentially be a convenience method
            // where a user wants to check a tumbler's paramters before commiting to tumbling (and therefore before configuring the runtime).

            // TODO: Temporary measure
            string[] args = { "-testnet" };

            var config = new TumblerClientConfiguration();

            config.LoadArgs(args);

            // AcceptAllClientConfiguration should be used if the interaction is null
            this.runtime = TumblerClientRuntime.FromConfiguration(config, null);

            //this.tumblerService = new TumblerService(serverAddress);
            //this.TumblerParameters = await this.tumblerService.GetClassicTumblerParametersAsync();
            this.TumblerParameters = runtime.TumblerParameters;

            if (this.TumblerParameters.Network != this.network)
            {
                throw new Exception($"The tumbler is on network {this.TumblerParameters.Network} while the wallet is on network {this.network}.");
            }

            // Load the current tumbling state fromt the file system
            this.tumblingState.LoadStateFromMemory();

            // Update and save the state
            this.tumblingState.TumblerUri        = serverAddress;
            this.tumblingState.TumblerParameters = this.TumblerParameters;
            this.tumblingState.Save();

            return(this.TumblerParameters);
        }
        public bool HasEnoughFundsForCycle(bool firstCycle, string originWalletName)
        {
            Money   walletBalance  = this.runtime.Services.WalletService.GetBalance(originWalletName);
            FeeRate networkFeeRate = this.runtime.Services.FeeService.GetFeeRateAsync().GetAwaiter().GetResult();

            return(TumblerClientRuntime.HasEnoughFundsForCycle(firstCycle, walletBalance, networkFeeRate, TumblerParameters.Denomination, TumblerParameters.Fee));
        }
示例#3
0
        public async Task RedeemEscrows(TumblerClientRuntime runtime)
        {
            Logs.Client.LogInformation("Rescanning redeems");
            var rpc  = ((RPCBlockExplorerService)runtime.Services.BlockExplorerService).RPCClient;
            var rate = await runtime.Services.FeeService.GetFeeRateAsync();

            foreach (var unspent in await rpc.ListUnspentAsync(0, 99999999))
            {
                foreach (var record in runtime.Tracker.Search(unspent.ScriptPubKey))
                {
                    if (record.TransactionType == Services.TransactionType.ClientEscrow)
                    {
                        Logs.Client.LogInformation("Client Escrow found " + record.TransactionId);
                        var cycle        = runtime.TumblerParameters.CycleGenerator.GetCycle(record.Cycle);
                        var machineState = runtime.CreateStateMachineJob().GetPaymentStateMachineState(cycle);
                        var solver       = new PaymentStateMachine(runtime, machineState).SolverClientSession;
                        var broadcast    = solver.CreateRedeemTransaction(rate);
                        runtime.Services.TrustedBroadcastService.Broadcast(cycle.Start, Services.TransactionType.ClientRedeem, new CorrelationId(solver.Id), broadcast);
                    }
                }
            }
            var lockedOutpoint = await rpc.ListLockUnspentAsync();

            await rpc.UnlockUnspentAsync(lockedOutpoint);

            Logs.Client.LogInformation("Unlocking " + lockedOutpoint.Length + " outpoints");
        }
 public ClientInteractiveRuntime(TumblerClientRuntime runtime)
 {
     if (runtime == null)
     {
         throw new ArgumentNullException("runtime");
     }
     InnerRuntime = runtime;
 }
        private async Task <Result <ClassicTumblerParameters> > TryUseServer()
        {
            logger.LogInformation($"Attempting connection to the masternode at address {this.TumblerAddress}");

            this.TumblingState.TumblerUri = new Uri(this.TumblerAddress);

            FullNodeTumblerClientConfiguration config;

            if (!UseTor)
            {
                config = new FullNodeTumblerClientConfiguration(this.TumblingState, onlyMonitor: false,
                                                                connectionTest: true, useProxy: false);
            }
            else
            {
                config = new FullNodeTumblerClientConfiguration(this.TumblingState, onlyMonitor: false,
                                                                connectionTest: true, useProxy: true);
            }

            TumblerClientRuntime rt = null;

            try
            {
                rt = await TumblerClientRuntime.FromConfigurationAsync(config, TumblerProtocol, connectionTest : true)
                     .ConfigureAwait(false);

                // This is overwritten by the tumble method, but it is needed at the beginning of that method for the balance check
                this.TumblerParameters = rt.TumblerParameters;

                //Check if the Server parameters are standard and do not connect if the parameters are non-standard
                if (!rt.TumblerParameters.IsStandard())
                {
                    this.logger.LogDebug($"Refusing to connect to the non-standard MasterNode {this.TumblerAddress}");
                    return(Result.Fail <ClassicTumblerParameters>($"Cannot connect to the MasterNode server {this.TumblerAddress} because its parameters are non-standard.", PostResultActionType.CanContinue));
                }

                return(Result.Ok(rt.TumblerParameters));
            }
            catch (PrivacyProtocolConfigException e)
            {
                this.logger.LogError(e, "Privacy protocol exception: {0}", e.Message);
                return(Result.Fail <ClassicTumblerParameters>("TOR is required for connectivity to an active Stratis Masternode. Please restart Breeze Wallet with Privacy Protocol and ensure that an instance of TOR is running.", PostResultActionType.ShouldStop));
            }
            catch (ConfigException e)
            {
                this.logger.LogError(e, "Privacy protocol config exception: {0}", e.Message);
                return(Result.Fail <ClassicTumblerParameters>(e.Message, PostResultActionType.CanContinue));
            }
            catch (Exception e)
            {
                this.logger.LogError(e, "Error obtaining tumbler parameters: {0}", e.Message);
                return(Result.Fail <ClassicTumblerParameters>("Error obtaining tumbler parameters", PostResultActionType.CanContinue));
            }
            finally
            {
                rt?.Dispose();
            }
        }
示例#6
0
        public void Run(string[] args)
        {
            var argsConf = new TextFileConfiguration(args);
            var debug    = argsConf.GetOrDefault <bool>("debug", false);
            ConsoleLoggerProcessor loggerProcessor = new ConsoleLoggerProcessor();

            Logs.Configure(new FuncLoggerFactory(i => new CustomerConsoleLogger(i, Logs.SupportDebug(debug), false, loggerProcessor)));
            using (var interactive = new Interactive())
            {
                try
                {
                    var config = new TumblerClientConfiguration();
                    config.LoadArgs(args);

                    var runtime = TumblerClientRuntime.FromConfiguration(config, new TextWriterClientInteraction(Console.Out, Console.In));
                    interactive.Runtime = new ClientInteractiveRuntime(runtime);


                    var broadcaster = runtime.CreateBroadcasterJob();
                    broadcaster.Start();
                    interactive.Services.Add(broadcaster);
                    //interactive.Services.Add(new CheckIpService(runtime));
                    //interactive.Services.Last().Start();

                    if (!config.OnlyMonitor)
                    {
                        var stateMachine = runtime.CreateStateMachineJob();
                        stateMachine.Start();
                        interactive.Services.Add(stateMachine);
                    }

                    interactive.StartInteractive();
                }
                catch (ClientInteractionException ex)
                {
                    if (!string.IsNullOrEmpty(ex.Message))
                    {
                        Logs.Configuration.LogError(ex.Message);
                    }
                }
                catch (ConfigException ex)
                {
                    if (!string.IsNullOrEmpty(ex.Message))
                    {
                        Logs.Configuration.LogError(ex.Message);
                    }
                }
                catch (InterruptedConsoleException) { }
                catch (Exception ex)
                {
                    Logs.Configuration.LogError(ex.Message);
                    Logs.Configuration.LogDebug(ex.StackTrace);
                }
            }
        }
        public async Task Initialize()
        {
            // Start broadcasterJob (onlymonitor mode)
            if (this.broadcasterJob == null || !this.broadcasterJob.Started)
            {
                var config = new FullNodeTumblerClientConfiguration(this.TumblingState, onlyMonitor: true);
                this.runtime = await TumblerClientRuntime.FromConfigurationAsync(config).ConfigureAwait(false);

                this.broadcasterJob = this.runtime.CreateBroadcasterJob();
                this.broadcasterJob.Start();
            }
        }
示例#8
0
        private async Task <Result <ClassicTumblerParameters> > TryUseServer()
        {
            logger.LogInformation($"Attempting connection to the masternode at address {this.TumblerAddress}");

            this.tumblingState.TumblerUri = new Uri(this.TumblerAddress);

            FullNodeTumblerClientConfiguration config;

            if (this.TumblerAddress.Contains("127.0.0.1"))
            {
                config = new FullNodeTumblerClientConfiguration(this.tumblingState, onlyMonitor: false,
                                                                connectionTest: true, useProxy: false);
            }
            else
            {
                config = new FullNodeTumblerClientConfiguration(this.tumblingState, onlyMonitor: false,
                                                                connectionTest: true, useProxy: true);
            }

            TumblerClientRuntime rt = null;

            try
            {
                rt = await TumblerClientRuntime.FromConfigurationAsync(config, connectionTest : true)
                     .ConfigureAwait(false);

                // This is overwritten by the tumble method, but it is needed at the beginning of that method for the balance check
                this.TumblerParameters = rt.TumblerParameters;

                return(Result.Ok(rt.TumblerParameters));
            }
            catch (PrivacyProtocolConfigException e)
            {
                this.logger.LogError(e, "Privacy protocol exception: {0}", e.Message);
                return(Result.Fail <ClassicTumblerParameters>("TOR is required for connectivity to an active Stratis Masternode. Please restart Breeze Wallet with Privacy Protocol and ensure that an instance of TOR is running.", false));
            }
            catch (ConfigException e)
            {
                this.logger.LogError(e, "Privacy protocol config exception: {0}", e.Message);
                return(Result.Fail <ClassicTumblerParameters>(e.Message, true));
            }
            catch (Exception e)
            {
                this.logger.LogError(e, "Error obtaining tumbler parameters: {0}", e.Message);
                return(Result.Fail <ClassicTumblerParameters>("Error obtaining tumbler parameters", true));
            }
            finally
            {
                rt?.Dispose();
            }
        }
        public TumblerServerTester(string directory, bool shouldBeStandard)
        {
            try
            {
                var rootTestData = "TestData";
                directory  = rootTestData + "/" + directory;
                _Directory = directory;
                if (!Directory.Exists(rootTestData))
                {
                    Directory.CreateDirectory(rootTestData);
                }

                if (!TryDelete(directory, false))
                {
                    foreach (var process in Process.GetProcessesByName("bitcoind"))
                    {
                        if (process.MainModule.FileName.Replace("\\", "/").StartsWith(Path.GetFullPath(rootTestData).Replace("\\", "/"), StringComparison.Ordinal))
                        {
                            process.Kill();
                            process.WaitForExit();
                        }
                    }
                    TryDelete(directory, true);
                }

                _NodeBuilder = NodeBuilder.Create(directory);
                _NodeBuilder.ConfigParameters.Add("prematurewitness", "1");
                _NodeBuilder.ConfigParameters.Add("walletprematurewitness", "1");

                _TumblerNode = _NodeBuilder.CreateNode(false);
                _AliceNode   = _NodeBuilder.CreateNode(false);
                _BobNode     = _NodeBuilder.CreateNode(false);

                Directory.CreateDirectory(directory);

                _NodeBuilder.StartAll();

                //Activate segwit
                SyncNodes();
                _TumblerNode.Generate(440);
                _TumblerNode.CreateRPCClient().SendToAddress(_AliceNode.CreateRPCClient().GetNewAddress(), Money.Coins(100m));
                _TumblerNode.Generate(1);
                SyncNodes();

                var conf = new TumblerConfiguration();
                conf.DataDir = Path.Combine(directory, "server");
                Directory.CreateDirectory(conf.DataDir);
                File.WriteAllBytes(Path.Combine(conf.DataDir, "Tumbler.pem"), TestKeys.Default.ToBytes());
                File.WriteAllBytes(Path.Combine(conf.DataDir, "Voucher.pem"), TestKeys.Default2.ToBytes());

                conf.RPC.Url = TumblerNode.CreateRPCClient().Address;
                var creds = ExtractCredentials(File.ReadAllText(_TumblerNode.Config));
                conf.RPC.User      = creds.Item1;
                conf.RPC.Password  = creds.Item2;
                conf.TorMandatory  = false;
                conf.Network       = Network.RegTest;
                conf.Listen        = new System.Net.IPEndPoint(IPAddress.Parse("127.0.0.1"), 5000);
                conf.AllowInsecure = !shouldBeStandard;

                conf.NoRSAProof = !shouldBeStandard;
                if (!shouldBeStandard)
                {
                    conf.ClassicTumblerParameters.FakePuzzleCount                 = 10;
                    conf.ClassicTumblerParameters.FakeTransactionCount            = 10;
                    conf.ClassicTumblerParameters.RealTransactionCount            = 10;
                    conf.ClassicTumblerParameters.RealPuzzleCount                 = 2;
                    conf.ClassicTumblerParameters.CycleGenerator.FirstCycle.Start = 105;
                }
                else
                {
                    var standard = new StandardCycles(conf.Network).Shorty2x;
                    conf.ClassicTumblerParameters.CycleGenerator = standard.Generator;
                    conf.ClassicTumblerParameters.Denomination   = standard.Denomination;
                }

                var runtime = TumblerRuntime.FromConfiguration(conf, new AcceptAllClientInteraction());
                _Host = new WebHostBuilder()
                        .UseAppConfiguration(runtime)
                        .UseContentRoot(Path.GetFullPath(directory))
                        .UseStartup <Startup>()
                        .Build();

                _Host.Start();
                ServerRuntime = runtime;

                //Overrides server fee
                ((RPCFeeService)runtime.Services.FeeService).FallBackFeeRate     = new FeeRate(Money.Satoshis(100), 1);
                ((RPCWalletService)runtime.Services.WalletService).BatchInterval = TimeSpan.FromMilliseconds(10);
                ((RPCWalletService)runtime.Services.WalletService).AddressGenerationBatchInterval = TimeSpan.FromMilliseconds(10);
                ((RPCBroadcastService)runtime.Services.BroadcastService).BatchInterval            = TimeSpan.FromMilliseconds(10);
                ((RPCBlockExplorerService)runtime.Services.BlockExplorerService).BatchInterval    = TimeSpan.FromMilliseconds(10);


                var clientConfig = new TumblerClientConfiguration();
                clientConfig.DataDir       = Path.Combine(directory, "client");
                clientConfig.AllowInsecure = !shouldBeStandard;
                Directory.CreateDirectory(clientConfig.DataDir);
                clientConfig.Network              = conf.Network;
                clientConfig.CheckIp              = false;
                clientConfig.TorMandatory         = false;
                clientConfig.OutputWallet.KeyPath = new KeyPath("0");
                clientConfig.OutputWallet.RootKey = new ExtKey().Neuter().GetWif(conf.Network);
                clientConfig.RPCArgs.Url          = AliceNode.CreateRPCClient().Address;
                creds = ExtractCredentials(File.ReadAllText(AliceNode.Config));
                clientConfig.RPCArgs.User     = creds.Item1;
                clientConfig.RPCArgs.Password = creds.Item2;
                clientConfig.TumblerServer    = runtime.TumblerUris.First();

                ClientRuntime = TumblerClientRuntime.FromConfiguration(clientConfig, new AcceptAllClientInteraction());

                //Overrides client fee
                ((RPCFeeService)ClientRuntime.Services.FeeService).FallBackFeeRate = new FeeRate(Money.Satoshis(50), 1);
            }
            catch { Dispose(); throw; }
        }
示例#10
0
 public CheckIpService(TumblerClientRuntime runtime)
 {
     this.runtime = runtime;
 }
示例#11
0
        /// <inheritdoc />
        public async Task TumbleAsync(string originWalletName, string destinationWalletName, string originWalletPassword)
        {
            // Make sure it won't start new tumbling round if already started
            if (this.State == TumbleState.Tumbling)
            {
                this.logger.LogDebug("Tumbler is already running");
                throw new Exception("Tumbling is already running");
            }

            this.tumblingState.TumblerUri = new Uri(this.TumblerAddress);

            // Check if in initial block download
            if (!this.chain.IsDownloaded())
            {
                this.logger.LogDebug("Chain is still being downloaded: " + this.chain.Tip);
                throw new Exception("Chain is still being downloaded");
            }

            Wallet destinationWallet = this.walletManager.GetWallet(destinationWalletName);
            Wallet originWallet      = this.walletManager.GetWallet(originWalletName);

            // Check if origin wallet has a sufficient balance to begin tumbling at least 1 cycle
            Money originBalance = this.walletManager.GetSpendableTransactionsInWallet(this.tumblingState.OriginWalletName)
                                  .Sum(s => s.Transaction.Amount);

            // Should ideally take network's transaction fee into account too, but that is dynamic
            if (originBalance <= (this.TumblerParameters.Denomination + this.TumblerParameters.Fee))
            {
                this.logger.LogDebug("Insufficient funds in origin wallet");
                throw new Exception("Insufficient funds in origin wallet");
            }

            // Check if password is valid before starting any cycles
            try
            {
                HdAddress tempAddress = originWallet.GetAccountsByCoinType(this.tumblingState.CoinType).First()
                                        .GetFirstUnusedReceivingAddress();
                originWallet.GetExtendedPrivateKeyForAddress(originWalletPassword, tempAddress);
            }
            catch (Exception)
            {
                this.logger.LogDebug("Origin wallet password appears to be invalid");
                throw new Exception("Origin wallet password appears to be invalid");
            }

            // Update the state and save
            this.tumblingState.DestinationWallet     = destinationWallet ?? throw new Exception($"Destination wallet not found. Have you created a wallet with name {destinationWalletName}?");
            this.tumblingState.DestinationWalletName = destinationWalletName;
            this.tumblingState.OriginWallet          = originWallet ?? throw new Exception($"Origin wallet not found. Have you created a wallet with name {originWalletName}?");
            this.tumblingState.OriginWalletName      = originWalletName;
            this.tumblingState.OriginWalletPassword  = originWalletPassword;

            var accounts = this.tumblingState.DestinationWallet.GetAccountsByCoinType(this.tumblingState.CoinType);
            // TODO: Possibly need to preserve destination account name in tumbling state. Default to first account for now
            string    accountName = accounts.First().Name;
            HdAccount destAccount = this.tumblingState.DestinationWallet.GetAccountByCoinType(accountName, this.tumblingState.CoinType);
            string    key         = destAccount.ExtendedPubKey;
            KeyPath   keyPath     = new KeyPath("0");

            // Stop and dispose onlymonitor
            if (this.broadcasterJob != null && this.broadcasterJob.Started)
            {
                await this.broadcasterJob.Stop().ConfigureAwait(false);
            }
            this.runtime?.Dispose();

            // Bypass Tor for integration tests
            FullNodeTumblerClientConfiguration config;

            if (this.TumblerAddress.Contains("127.0.0.1"))
            {
                config = new FullNodeTumblerClientConfiguration(this.tumblingState, onlyMonitor: false,
                                                                connectionTest: false, useProxy: false);
            }
            else
            {
                config = new FullNodeTumblerClientConfiguration(this.tumblingState, onlyMonitor: false,
                                                                connectionTest: false, useProxy: true);
            }

            this.runtime = await TumblerClientRuntime.FromConfigurationAsync(config).ConfigureAwait(false);

            BitcoinExtPubKey extPubKey = new BitcoinExtPubKey(key, this.runtime.Network);

            if (key != null)
            {
                this.runtime.DestinationWallet =
                    new ClientDestinationWallet(extPubKey, keyPath, this.runtime.Repository, this.runtime.Network);
            }
            this.TumblerParameters = this.runtime.TumblerParameters;

            // Run onlymonitor mode
            this.broadcasterJob = this.runtime.CreateBroadcasterJob();
            this.broadcasterJob.Start();

            // Run tumbling mode
            this.stateMachine = new StateMachinesExecutor(this.runtime);
            this.stateMachine.Start();

            this.State = TumbleState.Tumbling;
        }
示例#12
0
 public ClientInteractiveRuntime(TumblerClientRuntime runtime)
 {
     InnerRuntime = runtime ?? throw new ArgumentNullException("runtime");
 }
示例#13
0
        /// <inheritdoc />
        public async Task TumbleAsync(string originWalletName, string destinationWalletName, string originWalletPassword)
        {
            // Make sure it won't start new tumbling round if already started
            if (this.State == TumbleState.Tumbling)
            {
                this.logger.LogDebug("Tumbler is already running");
                throw new Exception("Tumbling is already running");
            }

            this.tumblingState.TumblerUri = new Uri(this.TumblerAddress);

            // Check if in initial block download
            if (!this.chain.IsDownloaded())
            {
                this.logger.LogDebug("Chain is still being downloaded: " + this.chain.Tip);
                throw new Exception("Chain is still being downloaded");
            }

            Wallet destinationWallet = this.walletManager.GetWallet(destinationWalletName);
            Wallet originWallet      = this.walletManager.GetWallet(originWalletName);

            // Check if origin wallet has a balance
            WalletBalanceModel model = new WalletBalanceModel();

            var originWalletAccounts = this.walletManager.GetAccounts(originWallet.Name).ToList();
            var originConfirmed      = new Money(0);
            var originUnconfirmed    = new Money(0);

            foreach (var originAccount in originWallet.GetAccountsByCoinType(this.tumblingState.CoinType))
            {
                var result = originAccount.GetSpendableAmount();

                originConfirmed   += result.ConfirmedAmount;
                originUnconfirmed += result.UnConfirmedAmount;
            }

            // Should ideally take network transaction fee into account too, but that is dynamic
            if ((originConfirmed + originUnconfirmed) <= (this.TumblerParameters.Denomination + this.TumblerParameters.Fee))
            {
                this.logger.LogDebug("Insufficient funds in origin wallet");
                throw new Exception("Insufficient funds in origin wallet");
            }

            // TODO: Check if password is valid before starting any cycles

            // Update the state and save
            this.tumblingState.DestinationWallet     = destinationWallet ?? throw new Exception($"Destination wallet not found. Have you created a wallet with name {destinationWalletName}?");
            this.tumblingState.DestinationWalletName = destinationWalletName;
            this.tumblingState.OriginWallet          = originWallet ?? throw new Exception($"Origin wallet not found. Have you created a wallet with name {originWalletName}?");
            this.tumblingState.OriginWalletName      = originWalletName;
            this.tumblingState.OriginWalletPassword  = originWalletPassword;

            var accounts = this.tumblingState.DestinationWallet.GetAccountsByCoinType(this.tumblingState.CoinType);
            // TODO: Possibly need to preserve destination account name in tumbling state. Default to first account for now
            string accountName = null;

            foreach (var account in accounts)
            {
                if (account.Index == 0)
                {
                    accountName = account.Name;
                }
            }
            var destAccount = this.tumblingState.DestinationWallet.GetAccountByCoinType(accountName, this.tumblingState.CoinType);

            var key     = destAccount.ExtendedPubKey;
            var keyPath = new KeyPath("0");

            // Stop and dispose onlymonitor
            if (this.broadcasterJob != null && this.broadcasterJob.Started)
            {
                await this.broadcasterJob.Stop().ConfigureAwait(false);
            }
            this.runtime?.Dispose();

            // Bypass Tor for integration tests
            FullNodeTumblerClientConfiguration config;

            if (this.TumblerAddress.Contains("127.0.0.1"))
            {
                config = new FullNodeTumblerClientConfiguration(this.tumblingState, onlyMonitor: false,
                                                                connectionTest: false, useProxy: false);
            }
            else
            {
                config = new FullNodeTumblerClientConfiguration(this.tumblingState, onlyMonitor: false,
                                                                connectionTest: false, useProxy: true);
            }

            this.runtime = await TumblerClientRuntime.FromConfigurationAsync(config).ConfigureAwait(false);

            var extPubKey = new BitcoinExtPubKey(key, this.runtime.Network);

            if (key != null)
            {
                this.runtime.DestinationWallet =
                    new ClientDestinationWallet(extPubKey, keyPath, this.runtime.Repository, this.runtime.Network);
            }
            this.TumblerParameters = this.runtime.TumblerParameters;
            // Run onlymonitor mode
            this.broadcasterJob = this.runtime.CreateBroadcasterJob();
            this.broadcasterJob.Start();

            // Run tumbling mode
            this.stateMachine = new StateMachinesExecutor(this.runtime);
            this.stateMachine.Start();

            this.State = TumbleState.Tumbling;

            return;
        }
示例#14
0
        /// <inheritdoc />
        public async Task <Result <ClassicTumblerParameters> > ConnectToTumblerAsync()
        {
            // Temporary hardcoding for testnet
            if (this.TumblerAddress == null)
            {
                this.TumblerAddress = "ctb://6cvi6ulcd4qn42mi.onion?h=95cb936fde9ae1856bcfd953746c26724a25dc46";
            }

            // If the -ppuri command line option wasn't used to bypass the registration store lookup
            if (this.TumblerAddress == null)
            {
                List <RegistrationRecord> registrations = this.registrationStore.GetAll();

                if (registrations.Count < MINIMUM_MASTERNODE_COUNT)
                {
                    this.logger.LogDebug("Not enough masternode registrations downloaded yet: " + registrations.Count);
                    return(null);
                }

                RegistrationRecord record            = null;
                RegistrationToken  registrationToken = null;
                bool validRegistrationFound          = false;

                // TODO: Search the registration store more robustly
                for (int i = 1; i < 10; i++)
                {
                    record            = registrations[random.Next(registrations.Count)];
                    registrationToken = record.Record;

                    // Implicitly, the registration feature will have deleted the registration if the collateral
                    // requirement was not met within 30 blocks
                    if ((this.walletManager.LastBlockHeight() - record.BlockReceived) >= 32)
                    {
                        validRegistrationFound = true;
                        break;
                    }
                }

                if (!validRegistrationFound)
                {
                    this.logger.LogDebug("Did not find a valid registration");
                    return(Result.Fail <ClassicTumblerParameters>("Did not find a valid registration"));
                }

                this.TumblerAddress = "ctb://" + registrationToken.OnionAddress + ".onion?h=" + registrationToken.ConfigurationHash;
            }

            this.tumblingState.TumblerUri = new Uri(this.TumblerAddress);

            FullNodeTumblerClientConfiguration config;

            if (this.TumblerAddress.Contains("127.0.0.1"))
            {
                config = new FullNodeTumblerClientConfiguration(this.tumblingState, onlyMonitor: false,
                                                                connectionTest: true, useProxy: false);
            }
            else
            {
                config = new FullNodeTumblerClientConfiguration(this.tumblingState, onlyMonitor: false,
                                                                connectionTest: true, useProxy: true);
            }

            TumblerClientRuntime rt = null;

            try
            {
                rt = await TumblerClientRuntime.FromConfigurationAsync(config, connectionTest : true)
                     .ConfigureAwait(false);

                // This is overwritten by the tumble method, but it is needed at the beginning of that method for the balance check
                this.TumblerParameters = rt.TumblerParameters;

                return(Result.Ok(rt.TumblerParameters));
            }
            catch (Exception cex) when(cex is PrivacyProtocolConfigException || cex is ConfigException)
            {
                this.logger.LogError("Error obtaining tumbler parameters: " + cex);
                return(Result.Fail <ClassicTumblerParameters>(
                           cex is PrivacyProtocolConfigException
                        ? "Tor is required for connectivity to an active Stratis Masternode. Please restart Breeze Wallet with Privacy Protocol and ensure that an instance of Tor is running."
                        : cex.Message));
            }
            catch (Exception e)
            {
                this.logger.LogError("Error obtaining tumbler parameters: " + e);
                return(Result.Fail <ClassicTumblerParameters>("Error obtaining tumbler parameters"));
            }
            finally
            {
                rt?.Dispose();
            }
        }
示例#15
0
        /// <inheritdoc />
        public async Task <ClassicTumblerParameters> ConnectToTumblerAsync()
        {
            if (this.network == Network.TestNet)
            {
                this.TumblerAddress = "ctb://sz64kj6ev5576w34.onion?h=ceced829426faf63cb906b99e5ee1ff83f001a95";
            }
            else
            {
                this.TumblerAddress = "ctb://frspe6yz6en4wbrt.onion?h=14dad7205ff3632f5ab903b9052116397bf7302f";
            }

            // If the -ppuri command line option wasn't used to bypass the registration store lookup
            if (this.TumblerAddress == null)
            {
                List <RegistrationRecord> registrations = this.registrationStore.GetAll();

                if (registrations.Count < MINIMUM_MASTERNODE_COUNT)
                {
                    this.logger.LogDebug("Not enough masternode registrations downloaded yet: " + registrations.Count);
                    return(null);
                }

                RegistrationRecord record            = null;
                RegistrationToken  registrationToken = null;
                bool validRegistrationFound          = false;

                // TODO: Search the registration store more robustly
                for (int i = 1; i < 10; i++)
                {
                    record            = registrations[random.Next(registrations.Count)];
                    registrationToken = record.Record;

                    // Implicitly, the registration feature will have deleted the registration if the collateral
                    // requirement was not met within 30 blocks
                    if ((this.walletManager.LastBlockHeight() - record.BlockReceived) >= 32)
                    {
                        validRegistrationFound = true;
                        break;
                    }
                }

                if (!validRegistrationFound)
                {
                    this.logger.LogDebug("Did not find a valid registration");
                    return(null);
                }

                this.TumblerAddress = "ctb://" + registrationToken.OnionAddress + ".onion?h=" + registrationToken.ConfigurationHash;
            }

            this.tumblingState.TumblerUri = new Uri(this.TumblerAddress);
            var config = new FullNodeTumblerClientConfiguration(this.tumblingState, onlyMonitor: false, connectionTest: true);
            TumblerClientRuntime rt = null;

            try
            {
                rt = await TumblerClientRuntime.FromConfigurationAsync(config, connectionTest : true).ConfigureAwait(false);

                // This is overwritten by the tumble method, but it is needed at the beginning of that method for the balance check
                this.TumblerParameters = rt.TumblerParameters;

                return(rt.TumblerParameters);
            }
            catch (Exception e)
            {
                this.logger.LogError("Error obtaining tumbler parameters: " + e);
                return(null);
            }
            finally
            {
                rt?.Dispose();
            }
        }
示例#16
0
        public TumblerServerTester(string directory)
        {
            try
            {
                var rootTestData = "TestData";
                directory  = rootTestData + "/" + directory;
                _Directory = directory;
                if (!Directory.Exists(rootTestData))
                {
                    Directory.CreateDirectory(rootTestData);
                }

                if (!TryDelete(directory, false))
                {
                    foreach (var process in Process.GetProcessesByName("bitcoind"))
                    {
                        if (process.MainModule.FileName.Replace("\\", "/").StartsWith(Path.GetFullPath(rootTestData).Replace("\\", "/"), StringComparison.Ordinal))
                        {
                            process.Kill();
                            process.WaitForExit();
                        }
                    }
                    TryDelete(directory, true);
                }

                _NodeBuilder = NodeBuilder.Create(directory);
                _TumblerNode = _NodeBuilder.CreateNode(false);
                _AliceNode   = _NodeBuilder.CreateNode(false);
                _BobNode     = _NodeBuilder.CreateNode(false);

                Directory.CreateDirectory(directory);

                _NodeBuilder.StartAll();

                SyncNodes();

                var conf = new TumblerConfiguration();
                conf.DataDir = Path.Combine(directory, "server");
                Directory.CreateDirectory(conf.DataDir);
                File.WriteAllBytes(Path.Combine(conf.DataDir, "Tumbler.pem"), TestKeys.Default.ToBytes());
                File.WriteAllBytes(Path.Combine(conf.DataDir, "Voucher.pem"), TestKeys.Default2.ToBytes());
                conf.RPC.Url = TumblerNode.CreateRPCClient().Address;
                var creds = ExtractCredentials(File.ReadAllText(_TumblerNode.Config));
                conf.RPC.User     = creds.Item1;
                conf.RPC.Password = creds.Item2;
                conf.Network      = Network.RegTest;
                conf.Listen.Add(new System.Net.IPEndPoint(IPAddress.Parse("127.0.0.1"), 5000));
                conf.ClassicTumblerParameters.FakePuzzleCount                /= 4;
                conf.ClassicTumblerParameters.FakeTransactionCount           /= 4;
                conf.ClassicTumblerParameters.RealTransactionCount           /= 4;
                conf.ClassicTumblerParameters.RealPuzzleCount                /= 4;
                conf.ClassicTumblerParameters.CycleGenerator.FirstCycle.Start = 105;

                var runtime = TumblerRuntime.FromConfiguration(conf, new AcceptAllClientInteraction());
                _Host = new WebHostBuilder()
                        .UseKestrel()
                        .UseAppConfiguration(runtime)
                        .UseContentRoot(Path.GetFullPath(directory))
                        .UseStartup <Startup>()
                        .UseUrls(conf.GetUrls())
                        .Build();

                _Host.Start();
                ServerRuntime = runtime;

                //Overrides server fee
                ((RPCFeeService)runtime.Services.FeeService).FallBackFeeRate = new FeeRate(Money.Satoshis(100), 1);


                var clientConfig = new TumblerClientConfiguration();
                clientConfig.DataDir       = Path.Combine(directory, "client");
                clientConfig.AllowInsecure = true;
                Directory.CreateDirectory(clientConfig.DataDir);
                clientConfig.Network = conf.Network;
                clientConfig.CheckIp = false;
                clientConfig.OutputWallet.KeyPath = new KeyPath("0");
                clientConfig.OutputWallet.RootKey = new ExtKey().Neuter().GetWif(conf.Network);
                clientConfig.RPCArgs.Url          = AliceNode.CreateRPCClient().Address;
                creds = ExtractCredentials(File.ReadAllText(AliceNode.Config));
                clientConfig.RPCArgs.User     = creds.Item1;
                clientConfig.RPCArgs.Password = creds.Item2;
                clientConfig.TumblerServer    = Address;

                ClientRuntime = TumblerClientRuntime.FromConfiguration(clientConfig, new AcceptAllClientInteraction());

                //Overrides client fee
                ((RPCFeeService)ClientRuntime.Services.FeeService).FallBackFeeRate = new FeeRate(Money.Satoshis(50), 1);
            }
            catch { Dispose(); throw; }
        }