Example #1
0
        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}.");
            }
        }
Example #2
0
        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.");
        }
Example #3
0
        /// <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.");
        }
Example #4
0
 public void SetupNetwork(TerabConfig config)
 {
     IpAddress = IPAddress.Parse(config.IpAddress);
     Port      = config.Port;
 }