Example #1
0
        public byte[] RecalculateHash(ulong root)
        {
            var node = GetNodeById(root);

            if (node is null)
            {
                return new byte[] {}
            }
            ;

            switch (node)
            {
            case InternalNode internalNode:
                List <byte[]> childrenHashes = new List <byte[]>();

                foreach (var child in internalNode.Children)
                {
                    childrenHashes.Add(GetNodeById(child).Hash);
                }

                return(childrenHashes
                       .Zip(InternalNode.GetChildrenLabels(internalNode.ChildrenMask), (bytes, i) => new[] { i }.Concat(bytes))
                       .SelectMany(bytes => bytes)
                       .KeccakBytes());

            case LeafNode leafNode:
                return(leafNode.KeyHash.Length.ToBytes().Concat(leafNode.KeyHash).Concat(leafNode.Value).KeccakBytes());
            }
            return(new byte[] {});
        }
Example #2
0
        private ulong ModifyInternalNode(ulong id, InternalNode node, byte h, ulong value, byte[]?valueHash)
        {
            if (value == 0 && node.GetChildByHash(h) != 0 && node.Children.Count() == 2)
            {
                // we have to handle case when one of two children is deleted and internal node is folded to leaf
                var secondChild = node.Children.First(child => child != node.GetChildByHash(h));
                // fold only if secondChild is also a leaf
                if (GetNodeById(secondChild).Type == NodeType.Leaf)
                {
                    return(secondChild);
                }
            }

            if (value != 0 && node.GetChildByHash(h) != 0 && node.Children.Count() == 1 && GetNodeById(value).Type == NodeType.Leaf)
            {
                return(value);
            }

            var modified = InternalNode.ModifyChildren(
                node, h, value,
                node.Children.Select(id => GetNodeById(id)?.Hash ?? throw new InvalidOperationException()),
                valueHash
                );

            if (modified == null)
            {
                return(0u);
            }
            var newId = _versionFactory.NewVersion();

            _nodeCache[newId] = modified;
            return(newId);
        }
Example #3
0
        public ulong InsertAllNodes(ulong root, IDictionary <ulong, IHashTrieNode> allTrieNodes)
        {
            if (root == 0)
            {
                return(0);
            }
            if (allTrieNodes.TryGetValue(root, out var node))
            {
                switch (node)
                {
                case InternalNode internalNode:

                    List <byte[]> childrenHash = new List <byte[]>();
                    List <ulong>  children     = new List <ulong>();
                    var           childrenMask = internalNode.ChildrenMask;

                    foreach (var child in internalNode.Children)
                    {
                        ulong childRoot = InsertAllNodes(child, allTrieNodes);
                        var   childNode = GetNodeById(childRoot);
                        children.Add(childRoot);
                        childrenHash.Add(childNode.Hash);
                    }
                    var newInternalNodeId = _versionFactory.NewVersion();
                    _nodeCache[newInternalNodeId] = new InternalNode(childrenMask, children, childrenHash);
                    return(newInternalNodeId);

                case LeafNode leafNode:
                    var newLeafNodeId = _versionFactory.NewVersion();
                    _nodeCache[newLeafNodeId] = leafNode;
                    return(newLeafNodeId);
                }
            }
            else
            {
                throw new InvalidOperationException();
            }
            return(0);
        }
Example #4
0
        private ulong SplitLeafNode(
            ulong id, LeafNode leafNode, int height, IReadOnlyList <byte> keyHash, IEnumerable <byte> value
            )
        {
            var firstFragment  = HashFragment(leafNode.KeyHash, height);
            var secondFragment = HashFragment(keyHash, height);

            if (firstFragment != secondFragment)
            {
                var secondSon     = NewLeafNode(keyHash, value);
                var secondSonHash = GetNodeById(secondSon)?.Hash;
                if (secondSonHash is null)
                {
                    throw new InvalidOperationException();
                }
                var newId = _versionFactory.NewVersion();
                _nodeCache[newId] = InternalNode.WithChildren(
                    new[] { id, secondSon },
                    new[] { firstFragment, secondFragment },
                    new[] { leafNode.Hash, secondSonHash }
                    );
                return(newId);
            }
            else
            {
                var son     = SplitLeafNode(id, leafNode, height + 1, keyHash, value);
                var sonHash = GetNodeById(son)?.Hash;
                if (sonHash is null)
                {
                    throw new InvalidOperationException();
                }
                var newId = _versionFactory.NewVersion();
                _nodeCache[newId] = InternalNode.WithChildren(new[] { son }, new[] { firstFragment }, new[] { sonHash });
                return(newId);
            }
        }
Example #5
0
        public static IHashTrieNode?ModifyChildren(
            InternalNode node, byte h, ulong value, IEnumerable <byte[]> childrenHashes, byte[]?valueHash
            )
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            var was = node.GetChildByHash(h);

            if (was == value)
            {
                return(node);
            }

            List <byte[]> newHashes;
            var           newNode = new InternalNode();
            var           pos     = (int)BitsUtils.PositionOf(node.ChildrenMask, h);

            if (was == 0)
            {
                if (valueHash is null)
                {
                    throw new ArgumentNullException(nameof(valueHash));
                }
                newNode._children = new ulong[node._children.Length + 1];
                for (var i = 0; i <= node._children.Length; ++i)
                {
                    newNode._children[i] = i < pos ? node._children[i] : (i == pos ? value : node._children[i - 1]);
                }
                newNode.ChildrenMask = node.ChildrenMask | (1u << h);
                newHashes            = childrenHashes.ToList();
                newHashes.Insert(pos, valueHash);
                newNode.UpdateHash(newHashes, GetChildrenLabels(newNode.ChildrenMask));
                return(newNode);
            }

            if (value == 0)
            {
                if (node._children.Length == 1)
                {
                    return(null);
                }
                newNode._children = new ulong[node._children.Length - 1];
                for (var i = 0; i + 1 < node._children.Length; ++i)
                {
                    newNode._children[i] = i < pos ? node._children[i] : node._children[i + 1];
                }
                newNode.ChildrenMask = node.ChildrenMask ^ (1u << h);
                newHashes            = childrenHashes.ToList();
                newHashes.RemoveAt(pos);
                newNode.UpdateHash(newHashes, GetChildrenLabels(newNode.ChildrenMask));
                return(newNode);
            }

            newNode._children      = node._children.ToArray();
            newNode.ChildrenMask   = node.ChildrenMask;
            newNode._children[pos] = value;
            newHashes      = childrenHashes.ToList();
            newHashes[pos] = valueHash ?? throw new ArgumentNullException(nameof(valueHash));
            newNode.UpdateHash(newHashes, GetChildrenLabels(newNode.ChildrenMask));
            return(newNode);
        }