internal LogEntry Wrap <T>(T model) where T : ILogSerialized { var type = _typeProvider.Get(typeof(Page)).GetValueOrDefault(); var version = LogSerializeContext.FormatVersion; var @object = new LogObject { Timestamp = TimestampFactory.Now, Type = type, Version = version, Data = model }; @object.Hash = _hashProvider.ComputeHashBytes(@object); // FIXME: inefficient, cache the last value somewhere? var previousHash = new byte[0]; foreach (var item in _store.StreamEntries()) { previousHash = item.Hash; } var entry = new LogEntry { PreviousHash = previousHash, Timestamp = @object.Timestamp, Nonce = Crypto.Nonce(64U), Objects = new[] { @object } }; entry.HashRoot = _hashProvider.ComputeHashRootBytes(entry); entry.Hash = _hashProvider.ComputeHashBytes(entry); return(entry); }
public static void EntryCheck(this LogEntry entry, LogEntry previous, ILogEntryHashProvider hashProvider) { if (previous.Index + 1 != entry.Index) { var message = $"Invalid index: expected '{previous.Index + 1}' but was '{entry.Index}'"; throw new LogException(message); } if (!previous.Hash.SequenceEqual(entry.PreviousHash)) { var message = $"Invalid previous hash: expected '{Crypto.ToHexString(previous.Hash)}' but was '{Crypto.ToHexString(entry.PreviousHash)}'"; throw new LogException(message); } var hashRoot = hashProvider.ComputeHashRootBytes(entry); if (!hashRoot.SequenceEqual(entry.HashRoot)) { var message = $"Invalid hash root: expected '{Crypto.ToHexString(hashRoot)}' but was '{Crypto.ToHexString(entry.HashRoot)}'"; throw new LogException(message); } for (var i = 0; i < entry.Objects.Count; i++) { if (entry.Objects[i].Index == i) { continue; } var message = $"Invalid object index: expected '{i}' but was '{entry.Objects[i].Index}'"; throw new LogException(message); } var hash = hashProvider.ComputeHashBytes(entry); if (!hash.SequenceEqual(entry.Hash)) { var message = $"Invalid hash: expected '{Crypto.ToHexString(hash)}' but was '{Crypto.ToHexString(entry.Hash)}'"; throw new LogException(message); } }