Exemple #1
0
        public static MPTNode Decode(byte[] data)
        {
            if (data is null || data.Length == 0)
            {
                return(null);
            }

            MPTNode node;

            using (BinaryReader reader = new BinaryReader(new MemoryStream(data, false), Encoding.UTF8))
            {
                var nodeType = (NodeType)reader.ReadByte();
                switch (nodeType)
                {
                case NodeType.BranchNode:
                {
                    node = new BranchNode();
                    break;
                }

                case NodeType.ExtensionNode:
                {
                    node = new ExtensionNode();
                    break;
                }

                case NodeType.LeafNode:
                {
                    node = new LeafNode();
                    break;
                }

                default:
                    throw new System.InvalidOperationException();
                }

                node.DecodeSpecific(reader);
            }
            return(node);
        }
Exemple #2
0
        private bool Put(ref MPTNode node, byte[] path, MPTNode val)
        {
            switch (node)
            {
            case LeafNode leafNode:
            {
                if (val is LeafNode v)
                {
                    if (path.Length == 0)
                    {
                        node = v;
                        db.Put(node);
                        return(true);
                    }
                    var branch = new BranchNode();
                    branch.Children[BranchNode.ChildCount - 1] = leafNode;
                    Put(ref branch.Children[path[0]], path.Skip(1), v);
                    db.Put(branch);
                    node = branch;
                    return(true);
                }
                return(false);
            }

            case ExtensionNode extensionNode:
            {
                if (path.AsSpan().StartsWith(extensionNode.Key))
                {
                    var result = Put(ref extensionNode.Next, path.Skip(extensionNode.Key.Length), val);
                    if (result)
                    {
                        extensionNode.SetDirty();
                        db.Put(extensionNode);
                    }
                    return(result);
                }
                var     prefix     = extensionNode.Key.CommonPrefix(path);
                var     pathRemain = path.Skip(prefix.Length);
                var     keyRemain  = extensionNode.Key.Skip(prefix.Length);
                var     son        = new BranchNode();
                MPTNode grandSon1  = HashNode.EmptyNode();
                MPTNode grandSon2  = HashNode.EmptyNode();

                Put(ref grandSon1, keyRemain.Skip(1), extensionNode.Next);
                son.Children[keyRemain[0]] = grandSon1;

                if (pathRemain.Length == 0)
                {
                    Put(ref grandSon2, pathRemain, val);
                    son.Children[BranchNode.ChildCount - 1] = grandSon2;
                }
                else
                {
                    Put(ref grandSon2, pathRemain.Skip(1), val);
                    son.Children[pathRemain[0]] = grandSon2;
                }
                db.Put(son);
                if (prefix.Length > 0)
                {
                    var exNode = new ExtensionNode()
                    {
                        Key  = prefix,
                        Next = son,
                    };
                    db.Put(exNode);
                    node = exNode;
                }
                else
                {
                    node = son;
                }
                return(true);
            }

            case BranchNode branchNode:
            {
                bool result;
                if (path.Length == 0)
                {
                    result = Put(ref branchNode.Children[BranchNode.ChildCount - 1], path, val);
                }
                else
                {
                    result = Put(ref branchNode.Children[path[0]], path.Skip(1), val);
                }
                if (result)
                {
                    branchNode.SetDirty();
                    db.Put(branchNode);
                }
                return(result);
            }

            case HashNode hashNode:
            {
                MPTNode newNode;
                if (hashNode.IsEmptyNode)
                {
                    if (path.Length == 0)
                    {
                        newNode = val;
                    }
                    else
                    {
                        newNode = new ExtensionNode()
                        {
                            Key  = path,
                            Next = val,
                        };
                        db.Put(newNode);
                    }
                    node = newNode;
                    if (val is LeafNode)
                    {
                        db.Put(val);
                    }
                    return(true);
                }
                newNode = Resolve(hashNode);
                if (newNode is null)
                {
                    return(false);
                }
                node = newNode;
                return(Put(ref node, path, val));
            }

            default:
                throw new System.InvalidOperationException("Invalid node type.");
            }
        }