Example #1
0
        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);
            }
        }
        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);
        }