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 BreezeD 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("BreezeD"); 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 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 }