Beispiel #1
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);
        }
Beispiel #2
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);
        }