private static void ValidateConfig(TerabConfig config) { // ipAddress - 0.0.0.0 / 127.0.0.1 if (!(config.IpAddress.Equals("0.0.0.0") || config.IpAddress.Equals("127.0.0.1"))) { throw new ArgumentException( $"The only IP Addresses allowed are 0.0.0.0 and 127.0.0.1, but was {config.IpAddress}."); } // port > 1024, < 2^16 (65536) if (config.Port < 1025 || config.Port > 65536) { throw new ArgumentException($"The port has to be between 1025 and 65536, but was {config.Port}."); } }
public void SetupStores(TerabConfig config) { var secretPath = Path.Combine(config.Layer1Path, "secret.dat"); var secretStore = new MemoryMappedFileSlim(secretPath); var secretSpan = secretStore.GetSpan(0, Constants.SecretStoreFileSize); // HACK: secret initialization (would be better isolated) if (secretSpan.ToArray().All(b => b == 0)) { var rng = RandomNumberGenerator.Create(); rng.GetBytes(secretSpan); } OutpointHash = new SipHash(secretSpan); var chainPath = Path.Combine(config.Layer1Path, "chains.dat"); ChainStore = new ChainStore(new MemoryMappedFileSlim(chainPath), _log); ChainStore.Initialize(); CoinStores = new ICoinStore[Constants.CoinControllerCount]; for (var i = 0; i < Constants.CoinControllerCount; i++) { var journalPath = Path.Combine(config.Layer1Path, $"coins-journal-{i:x2}.dat"); var journalFile = new MemoryMappedFileSlim(journalPath); var layer1CoinStorePath = Path.Combine(config.Layer1Path, $"coins-1-{i:x2}.dat"); var layer1File = new MemoryMappedFileSlim(layer1CoinStorePath); var sectorCount = (int)(layer1File.FileLength / Constants.CoinStoreLayer1SectorSize); // Last layer used for key-value store. IKeyValueStore <uint> kvStore = null; if (!string.IsNullOrEmpty(config.Layer3Path)) { var layer3CoinStorePath = Path.Combine(config.Layer3Path, $"coins-3-{i:x2}.dat"); kvStore = new LightningStore <uint>(layer3CoinStorePath, "coins"); } IPackStore packStore; if (string.IsNullOrEmpty(config.Layer2Path)) { // Layer 2 is omitted packStore = new PackStore( sectorCount, new[] { Constants.CoinStoreLayer1SectorSize }, new[] { layer1File }, journalFile, kvStore, _log); } else { // Layer 2 is included var layer2CoinStorePath = Path.Combine(config.Layer2Path, $"coins-2-{i:x2}.dat"); var layer2File = new MemoryMappedFileSlim(layer2CoinStorePath); // Sector size on layer 2 is inferred from the sector count on layer 1. if (layer2File.FileLength % sectorCount != 0) { throw new InvalidOperationException("Mismatch between sector counts across layers."); } var coinStoreLayer1SectorSize = (int)(layer2File.FileLength / sectorCount); packStore = new PackStore( sectorCount, new[] { Constants.CoinStoreLayer1SectorSize, coinStoreLayer1SectorSize }, new[] { layer1File, layer2File }, journalFile, kvStore, _log); } packStore.Initialize(); CoinStores[i] = new SozuTable(packStore, OutpointHash); } _log?.Log(LogSeverity.Info, "Terab store initialization completed successfully."); }
/// <summary> /// Creates all the files with their pre-allocated sizes. /// </summary> public static void InitializeFiles(TerabConfig config, long layer1Capacity, long layer2Capacity = 0, ILog log = null) { log?.Log(LogSeverity.Info, "Starting Terab setup."); var sectorCount = layer1Capacity / (Constants.CoinControllerCount * Constants.CoinStoreLayer1SectorSize); var coinStoreLayer2SectorSize = (layer2Capacity / layer1Capacity) * Constants.CoinStoreLayer1SectorSize; log?.Log(LogSeverity.Info, $"Sector count: {sectorCount}"); // Queuing checks var files = new List <(string path, long fileLength)>(); var folders = new List <string>(); // Secret var secretPath = Path.Combine(config.Layer1Path, "secret.dat"); files.Add((secretPath, Constants.SecretStoreFileSize)); // Chain store var chainPath = Path.Combine(config.Layer1Path, "chains.dat"); files.Add((chainPath, Constants.ChainStoreFileSize)); // Coin stores for (var i = 0; i < Constants.CoinControllerCount; i++) { var journalPath = Path.Combine(config.Layer1Path, $"coins-journal-{i:x2}.dat"); files.Add((journalPath, Constants.CoinStoreJournalCapacity)); var layer1CoinStorePath = Path.Combine(config.Layer1Path, $"coins-1-{i:x2}.dat"); files.Add((layer1CoinStorePath, sectorCount * Constants.CoinStoreLayer1SectorSize)); if (!string.IsNullOrEmpty(config.Layer2Path)) { var layer2CoinStorePath = Path.Combine(config.Layer2Path, $"coins-2-{i:x2}.dat"); files.Add((layer2CoinStorePath, sectorCount * coinStoreLayer2SectorSize)); } if (string.IsNullOrEmpty(config.Layer3Path)) { log?.Log(LogSeverity.Info, $"Layer 3 path isn't defined."); } else { var layer3CoinStorePath = Path.Combine(config.Layer3Path, $"coins-3-{i:x2}.dat"); folders.Add(layer3CoinStorePath); } } // Look for conflicts before doing anything foreach (var(file, _) in files) { if (File.Exists(file)) { log?.Log(LogSeverity.Error, $"Can't initialize, file already exists: {file}."); return; } } foreach (var folder in folders) { if (Directory.Exists(folder)) { log?.Log(LogSeverity.Error, $"Can't initialize, folder already exists: {folder}."); return; } } var rollback = false; // Once checks are done, proceed { var currentFile = string.Empty; try { foreach (var(file, fileLength) in files) { currentFile = file; using (var mmf = MemoryMappedFile.CreateFromFile(currentFile, FileMode.CreateNew, mapName: null, capacity: fileLength)) { log?.Log(LogSeverity.Info, $"Created {file} of {fileLength} bytes."); } } } catch (Exception ex) // most likely failed because of disk full { log?.Log(LogSeverity.Error, $"Can't create file {currentFile}: {ex}."); rollback = true; } } { var currentFolder = string.Empty; try { foreach (var folder in folders) { currentFolder = folder; Directory.CreateDirectory(folder); using (var lmdb = new LightningStore <uint>(currentFolder, "coins")) { lmdb.RoundTrip(); } } } catch (Exception ex) // most likely failed because of disk permission { log?.Log(LogSeverity.Error, $"Can't create folder {currentFolder}: {ex}."); rollback = true; } } // Error(s) have been encountered, rolling back. if (rollback) { log?.Log(LogSeverity.Error, "Rolling back."); foreach (var(file, _) in files) { File.Delete(file); } log?.Log(LogSeverity.Error, "Roll back completed."); return; } log?.Log(LogSeverity.Info, "Terab file creation completed successfully."); }
public void SetupNetwork(TerabConfig config) { IpAddress = IPAddress.Parse(config.IpAddress); Port = config.Port; }