public static void Main(string[] args) { var serviceProvider = new ServiceCollection() .AddLogging() .AddSingleton <ITumblerService, TumblerService>() .BuildServiceProvider(); serviceProvider .GetService <ILoggerFactory>() .AddConsole(LogLevel.Debug); // TODO: It is messy having both a BreezeServer logger and an NTumbleBit logger var logger = serviceProvider.GetService <ILoggerFactory>() .CreateLogger <Program>(); logger.LogInformation("{Time} Reading Breeze server configuration", DateTime.Now); // Check OS-specific default config path for the config file. Create default file if it does not exist var configDir = BreezeConfiguration.GetDefaultDataDir("BreezeServer"); var configPath = Path.Combine(configDir, "breeze.conf"); logger.LogInformation("{Time} Configuration file path {Path}", DateTime.Now, configPath); var config = new BreezeConfiguration(configPath); var dbPath = Path.Combine(configDir, "db"); logger.LogInformation("{Time} Database path {Path}", DateTime.Now, dbPath); var db = new DBUtils(dbPath); logger.LogInformation("{Time} Checking node registration on the blockchain", DateTime.Now); var registration = new BreezeRegistration(); if (!registration.CheckBreezeRegistration(config, db)) { logger.LogInformation("{Time} Creating or updating node registration", DateTime.Now); var regTx = registration.PerformBreezeRegistration(config, db); if (regTx != null) { logger.LogInformation("{Time} Submitted transaction {TxId} via RPC for broadcast", DateTime.Now, regTx.GetHash().ToString()); } else { logger.LogInformation("{Time} Unable to broadcast transaction via RPC", DateTime.Now); Environment.Exit(0); } } else { logger.LogInformation("{Time} Node registration has already been performed", DateTime.Now); } logger.LogInformation("{Time} Starting Tumblebit server", DateTime.Now); db.UpdateOrInsert <string>("TumblerStartupLog", DateTime.Now.ToString("yyyyMMddHHmmss"), "Tumbler starting", (o, n) => n); var tumbler = serviceProvider.GetService <ITumblerService>(); tumbler.StartTumbler(config.IsTestNet); }
public static void Main(string[] args) { var comparer = new CommandlineArgumentComparer(); var isRegTest = args.Contains("regtest", comparer); var isTestNet = args.Contains("testnet", comparer); var forceRegistration = args.Contains("forceRegistration", comparer); var useTor = !args.Contains("noTor", comparer); TumblerProtocolType?tumblerProtocol = null; try { string tumblerProtocolString = args.Where(a => a.StartsWith("-tumblerProtocol=")).Select(a => a.Substring("-tumblerProtocol=".Length).Replace("\"", "")).FirstOrDefault(); if (!isRegTest && (tumblerProtocolString != null || !useTor)) { Console.WriteLine("Options -TumblerProtocol and -NoTor can only be used in combination with -RegTest switch."); return; } if (tumblerProtocolString != null) { tumblerProtocol = Enum.Parse <TumblerProtocolType>(tumblerProtocolString, true); } if (useTor && tumblerProtocol.HasValue && tumblerProtocol.Value == TumblerProtocolType.Http) { Console.WriteLine("TumblerProtocol can only be changed to Http when Tor is disabled. Please use -NoTor switch to disable Tor."); return; } } catch { Console.WriteLine($"Incorrect tumbling prococol specified; the valid values are {TumblerProtocolType.Tcp} and {TumblerProtocolType.Http}"); return; } var serviceProvider = new ServiceCollection() .AddLogging() .AddSingleton <ITumblerService, TumblerService>() .BuildServiceProvider(); serviceProvider .GetService <ILoggerFactory>() .AddConsole(LogLevel.Debug); // TODO: It is messy having both a BreezeServer logger and an NTumbleBit logger var logger = serviceProvider.GetService <ILoggerFactory>() .CreateLogger <Program>(); logger.LogInformation("{Time} Reading Breeze server configuration", DateTime.Now); // Check OS-specific default config path for the config file. Create default file if it does not exist string configDir = BreezeConfiguration.GetDefaultDataDir("BreezeServer"); if (isRegTest) { configDir = Path.Combine(configDir, "ImpleumRegTest"); } else if (isTestNet) { configDir = Path.Combine(configDir, "ImpleumTest"); } else { configDir = Path.Combine(configDir, "ImpleumMain"); } string configPath = Path.Combine(configDir, "breeze.conf"); logger.LogInformation("{Time} Configuration file path {Path}", DateTime.Now, configPath); BreezeConfiguration config = new BreezeConfiguration(configPath); if (!useTor) { config.UseTor = false; } logger.LogInformation("{Time} Pre-initialising server to obtain parameters for configuration", DateTime.Now); var preTumblerConfig = serviceProvider.GetService <ITumblerService>(); preTumblerConfig.StartTumbler(config, true, torMandatory: !isRegTest, tumblerProtocol: tumblerProtocol); string configurationHash = preTumblerConfig.runtime.ClassicTumblerParameters.GetHash().ToString(); string onionAddress = preTumblerConfig.runtime.TorUri.Host.Substring(0, 16); NTumbleBit.RsaKey tumblerKey = preTumblerConfig.runtime.TumblerKey; // No longer need this instance of the class if (config.UseTor) { preTumblerConfig.runtime.TorConnection.Dispose(); } preTumblerConfig = null; string regStorePath = Path.Combine(configDir, "registrationHistory.json"); logger.LogInformation("{Time} Registration history path {Path}", DateTime.Now, regStorePath); logger.LogInformation("{Time} Checking node registration", DateTime.Now); BreezeRegistration registration = new BreezeRegistration(); if (forceRegistration || !registration.CheckBreezeRegistration(config, regStorePath, configurationHash, onionAddress, tumblerKey)) { logger.LogInformation("{Time} Creating or updating node registration", DateTime.Now); var regTx = registration.PerformBreezeRegistration(config, regStorePath, configurationHash, onionAddress, tumblerKey); if (regTx != null) { logger.LogInformation("{Time} Submitted transaction {TxId} via RPC for broadcast", DateTime.Now, regTx.GetHash().ToString()); } else { logger.LogInformation("{Time} Unable to broadcast transaction via RPC", DateTime.Now); Environment.Exit(0); } } else { logger.LogInformation("{Time} Node registration has already been performed", DateTime.Now); } // Perform collateral balance check and report the result Money collateralShortfall; if (registration.VerifyCollateral(config, out collateralShortfall)) { logger.LogInformation($"{{Time}} The collateral address {config.TumblerEcdsaKeyAddress} has sufficient funds.", DateTime.Now); } else { logger.LogWarning($"{{Time}} The collateral address {config.TumblerEcdsaKeyAddress} doesn't have enough funds. Collateral requirement is {RegistrationParameters.MASTERNODE_COLLATERAL_THRESHOLD} but only {collateralShortfall} is available at the collateral address. This is expected if you have only just run the masternode for the first time. Please send funds to the collateral address no later than {RegistrationParameters.WINDOW_PERIOD_BLOCK_COUNT} blocks after the registration transaction.", DateTime.Now); } logger.LogInformation("{Time} Starting Tumblebit server", DateTime.Now); // The TimeStamp and BlockSignature flags could be set to true when the Stratis network is instantiated. // We need to set it to false here to ensure compatibility with the Bitcoin protocol. Transaction.TimeStamp = false; Block.BlockSignature = false; var tumbler = serviceProvider.GetService <ITumblerService>(); tumbler.StartTumbler(config, false, torMandatory: !isRegTest, tumblerProtocol: tumblerProtocol); }
public static void Main(string[] args) { var serviceProvider = new ServiceCollection() .AddLogging() .AddSingleton <ITumblerService, TumblerService>() .BuildServiceProvider(); serviceProvider .GetService <ILoggerFactory>() .AddConsole(LogLevel.Debug); // TODO: It is messy having both a BreezeServer logger and an NTumbleBit logger var logger = serviceProvider.GetService <ILoggerFactory>() .CreateLogger <Program>(); logger.LogInformation("{Time} Reading Breeze server configuration", DateTime.Now); // Check OS-specific default config path for the config file. Create default file if it does not exist string configDir = BreezeConfiguration.GetDefaultDataDir("BreezeServer"); string configPath = Path.Combine(configDir, "breeze.conf"); logger.LogInformation("{Time} Configuration file path {Path}", DateTime.Now, configPath); BreezeConfiguration config = new BreezeConfiguration(configPath); logger.LogInformation("{Time} Pre-initialising server to obtain parameters for configuration", DateTime.Now); var preTumblerConfig = serviceProvider.GetService <ITumblerService>(); preTumblerConfig.StartTumbler(config.IsTestNet, true); string configurationHash = preTumblerConfig.runtime.ClassicTumblerParameters.GetHash().ToString(); string onionAddress = preTumblerConfig.runtime.TorUri.Host.Substring(0, 16); NTumbleBit.RsaKey tumblerKey = preTumblerConfig.runtime.TumblerKey; // Mustn't be occupying hidden service URL when the TumblerService is reinitialised preTumblerConfig.runtime.TorConnection.Dispose(); // No longer need this instance of the class preTumblerConfig = null; string regStorePath = Path.Combine(configDir, "registrationHistory.json"); logger.LogInformation("{Time} Registration history path {Path}", DateTime.Now, regStorePath); logger.LogInformation("{Time} Checking node registration", DateTime.Now); BreezeRegistration registration = new BreezeRegistration(); if (!registration.CheckBreezeRegistration(config, regStorePath, configurationHash, onionAddress, tumblerKey)) { logger.LogInformation("{Time} Creating or updating node registration", DateTime.Now); var regTx = registration.PerformBreezeRegistration(config, regStorePath, configurationHash, onionAddress, tumblerKey); if (regTx != null) { logger.LogInformation("{Time} Submitted transaction {TxId} via RPC for broadcast", DateTime.Now, regTx.GetHash().ToString()); } else { logger.LogInformation("{Time} Unable to broadcast transaction via RPC", DateTime.Now); Environment.Exit(0); } } else { logger.LogInformation("{Time} Node registration has already been performed", DateTime.Now); } logger.LogInformation("{Time} Starting Tumblebit server", DateTime.Now); var tumbler = serviceProvider.GetService <ITumblerService>(); tumbler.StartTumbler(config.IsTestNet, false); }
public void ParseTransaction(Transaction tx, Network network) { if (tx.Outputs.Count < 2) { throw new Exception("Transaction does not have sufficient outputs"); } var breezeReg = new BreezeRegistration(); // Assume the nulldata transaction marker is the first output //var firstOutputData = breezeReg.AddressToBytes(tx.Outputs[0].ScriptPubKey.GetDestinationAddress(network)); // TODO: Validate that the marker bytes are present before proceeding // Peek at first non-nulldata address to get the length information, // this indicates if there will be a change address output or not var secondOutputData = breezeReg.AddressToBytes(tx.Outputs[1].ScriptPubKey.GetDestinationAddress(network)); var protocolVersion = (int)secondOutputData[0]; var headerLength = ((int)secondOutputData[2] << 8) + ((int)secondOutputData[1]); int numAddresses = headerLength / 20; if (headerLength % 20 != 0) { numAddresses++; } if (tx.Outputs.Count < (numAddresses + 1)) { throw new Exception("Too few addresses in transaction output, registration transaction incomplete"); } var addressList = new List <BitcoinAddress>(); for (var i = 1; i < (numAddresses + 1); i++) { addressList.Add(tx.Outputs[i].ScriptPubKey.GetDestinationAddress(network)); } var bitstream = breezeReg.AddressesToBytes(addressList); // Need to consume X bytes at a time off the bitstream and convert them to various // data types, then set member variables to the retrieved values. // Skip over protocol version and header length bytes var position = 3; ProtocolVersion = protocolVersion; // Either a valid IPv4 address, or all zero bytes bool allZeroes = true; byte[] ipv4temp = GetSubArray(bitstream, position, 4); for (var i = 0; i < ipv4temp.Length; i++) { if (ipv4temp[i] != 0) { allZeroes = false; } } if (!allZeroes) { Ipv4Addr = new IPAddress(ipv4temp); } else { Ipv4Addr = null; } position += 4; // Either a valid IPv6 address, or all zero bytes allZeroes = true; byte[] ipv6temp = GetSubArray(bitstream, position, 16); for (var i = 0; i < ipv6temp.Length; i++) { if (ipv6temp[i] != 0) { allZeroes = false; } } if (!allZeroes) { Ipv6Addr = new IPAddress(ipv6temp); } else { Ipv6Addr = null; } position += 16; // Either a valid onion address, or all zero bytes allZeroes = true; byte[] onionTemp = GetSubArray(bitstream, position, 16); for (var i = 0; i < onionTemp.Length; i++) { if (onionTemp[i] != 0) { allZeroes = false; } } if (!allZeroes) { OnionAddress = Encoding.ASCII.GetString(onionTemp); } else { OnionAddress = null; } position += 16; var temp = GetSubArray(bitstream, position, 2); Port = ((int)temp[1] << 8) + ((int)temp[0]); position += 2; temp = GetSubArray(bitstream, position, 2); var rsaLength = ((int)temp[1] << 8) + ((int)temp[0]); position += 2; RsaSignature = GetSubArray(bitstream, position, rsaLength); position += rsaLength; temp = GetSubArray(bitstream, position, 2); var ecdsaLength = ((int)temp[1] << 8) + ((int)temp[0]); position += 2; EcdsaSignature = GetSubArray(bitstream, position, ecdsaLength); position += ecdsaLength; // TODO: Validate signatures }