public void Initialize() { if (false == Directory.Exists(LedgerPath)) { Directory.CreateDirectory(LedgerPath); } Indexes.Initialize(); PhysicalBlock block = new PhysicalBlock(); block.Id = Indexes.GetNextBlockId(); block.LedgerId = Id; block.TransactionData = System.Text.Encoding.ASCII.GetBytes("ledger initialized"); block.SignBlock = new SignBlock(); block.ComputeHash(); LedgerIndex index = Indexes.Add(block.Hash, block.TimeStamp); if (block.Id != index.BlockID) { throw new LedgerException(Name, $"ID mismatch {block.Id}/{index.BlockID}"); } // TODO: these next two steps are technically a transaction, need to determine what happens when // one step fails. System.Console.WriteLine($"saving indexes to {LedgerIndexFileName}"); Indexes.Save(); }
public void Initialize() { if (false == Directory.Exists(LedgerPath)) { Directory.CreateDirectory(LedgerPath); } Indexes.Initialize(); PhysicalBlock block = new PhysicalBlock { Id = Indexes.GetNextBlockId(), LedgerId = Id, TransactionData = System.Text.Encoding.ASCII.GetBytes("ledger initialized"), SignBlock = new SignBlock() }; block.ComputeHash(); LedgerIndex index = Indexes.Add(block.Hash, block.TimeStamp); if (block.Id != index.BlockId) { throw new LedgerException(Name, $"ID mismatch {block.Id}/{index.BlockId}"); } // TODO: these next two steps are technically a transaction, need to determine what happens when // one step fails. _logger.LogInformation($"saving indexes to {LedgerIndexFileName}"); // step 1 save the block // TODO: need rollback if Indexes.Save() fails Writer.SaveBlock(block); // step 2 save the index Indexes.Save(); }
public static PhysicalBlock FromString(string data) { string[] elements = data.Split(":"); DateTime timeStamp; if (false == DateTime.TryParseExact(elements[5], Constants.DateTimeFormat, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out timeStamp)) { throw new LedgerNotValidException($"{elements[5]}"); } PhysicalBlock block = new PhysicalBlock() { ParentId = Convert.ToInt32(elements[0]), Id = Convert.ToInt32(elements[1]), ParentHash = elements[2], ReferenceId = Convert.ToInt32(elements[3]), LedgerId = Convert.ToInt32(elements[4]), TimeStamp = timeStamp, Nonce = Nonce.FromString(elements[6]), TransactionData = Encoding.UTF8.GetBytes(elements[7]) }; // compare hash from string with computedHash. they should match if (elements[8] != block.ComputeHash()) { throw new LedgerNotValidException($"block {block.Id}"); } return(block); }
public void Validate() { State = LedgerState.StartingUp; if (false == File.Exists(LedgerIndexFileName)) { throw new LedgerNotFoundException(LedgerIndexFileName); } try { Indexes.Load(); // Validation Rule #1: the number of records in the index file should match // the number of blocks saved on disk if (Reader.CountBlocks() != Indexes.Count()) { throw new LedgerNotValidException($"{Reader.CountBlocks()} != {Indexes.Count()}"); } // Validation Rule #2: the boot record (which is the very first record) // should be valid PhysicalBlock rootBlock = Reader.GetLedgerPhysicalBlock(1, (data) => { return(PhysicalBlock.FromString(data)); }) as PhysicalBlock; LedgerIndex rootIndex = Indexes.GetIndex(1); if (rootBlock.ComputeHash() != rootIndex.Hash) { throw new LedgerNotValidException($"block {rootBlock.Id}"); } // Validation Rule #3: the last record should validate // Validation Rule #4: verify a few other blocks // TODO: validate some of the remaining blocks. // TODO: have an option that requires all blocks to be validated State = LedgerState.Available; } catch (Exception e) { State = LedgerState.Nonfunctional; throw new LedgerException(Name, e); } }