Beispiel #1
0
        // 일치하는 키와 남은 키를 구한다.
        public TrieKey GetMatchKey(TrieKey key, out TrieKey keyRemain)
        {
            int count = Compare(key);

            keyRemain = Skip(count);
            return(Take(count));
        }
Beispiel #2
0
        protected void ToList(TrieNode node, TrieKey key, List <KeyValuePair <byte[], byte[]> > array)
        {
            if (node.Type == NodeType.ValueNode)
            {
                byte[] value = node.Value;
                if (!value.IsNullOrEmpty())
                {
                    array.Add(new KeyValuePair <byte[], byte[]>((key + node.Key).Path.ToByteArray(), value));
                }
            }
            else if (node.Type == NodeType.ShortNode)
            {
                ToList(node.Next, key + node.Key, array);
            }
            else if (node.Type == NodeType.FullNode)
            {
                byte[] value = node.Value;
                if (!value.IsNullOrEmpty())
                {
                    array.Add(new KeyValuePair <byte[], byte[]>(key.Path.ToByteArray(), value));
                }

                for (byte i = 0; i < 16; i++)
                {
                    var n = node.GetChild(i);
                    if (!ReferenceEquals(n, null))
                    {
                        ToList(n, key + new TrieKey(new Nibble[] { i }, true), array);
                    }
                }
            }
        }
Beispiel #3
0
        public int Compare(TrieKey key, out TrieKey keyRemain)
        {
            int count = Compare(key);

            keyRemain = Skip(count);
            return(count);
        }
Beispiel #4
0
 public void Dispose()
 {
     rlp      = null;
     key      = null;
     next     = null;
     chidrens = null;
     value    = null;
 }
Beispiel #5
0
        public static TrieKey operator +(TrieKey left, TrieKey right)
        {
            var key = new TrieKey();

            key.Push(left);
            key.Push(right);
            return(key);
        }
Beispiel #6
0
        // new extension node
        public TrieNode(ITrie trie, TrieKey key, TrieNode next)
        {
            this.trie = trie;
            rlp       = new RlpEncoder(key, next.Hash).Encode();

            Type  = NodeType.ShortNode;
            Dirty = true;

            DecodeRLP();
        }
Beispiel #7
0
        // new leaf node
        public TrieNode(ITrie trie, TrieKey key, byte[] value)
        {
            this.trie = trie;
            rlp       = new RlpEncoder(key, value).Encode();

            Type  = NodeType.ValueNode;
            Dirty = true;

            DecodeRLP();
        }
Beispiel #8
0
        // GET
        public byte[] Get(byte[] key)
        {
            if (!HasRoot)
            {
                return(null);
            }

            TrieKey  k    = GetTrieKey(key);
            TrieNode node = FindNode(RootNode, k).found;

            return(node != null ? node.Value : null);
        }
Beispiel #9
0
 public static NodeType GetNodeType(RlpDecoder rlp)
 {
     if (rlp.Count == 17)
     {
         return(NodeType.FullNode);
     }
     if (rlp.Count == 2)
     {
         return(TrieKey.Decode(rlp[0].Value).HasTerm ? NodeType.ValueNode : NodeType.ShortNode);
     }
     return(NodeType.EmptyNode);
 }
Beispiel #10
0
        // DELETE
        public void Del(byte[] key)
        {
            TrieKey k = GetTrieKey(key);

            if (HasRoot)
            {
                // 탐색 진행
                (TrieNode found, TrieKey keyRemainder, Stack <TrieNode> stack) = FindNode(RootNode, k);
                if (found != null)
                {
                    // 노드를 찾았으면 값을 삭제하고
                    // 스택을 저장한다.
                    found.Value = null;
                    RootNode    = SaveStack(k, stack);
                    return;
                }
            }
        }
Beispiel #11
0
        // PUT
        public void Put(byte[] key, byte[] value)
        {
            TrieKey k = GetTrieKey(key);

            if (!HasRoot)
            {
                RootNode = new TrieNode(this, k, value);
                return;
            }

            // 탐색 진행
            (TrieNode found, TrieKey keyRemainder, Stack <TrieNode> stack) = FindNode(RootNode, k);
            if (found != null)
            {
                // 노드를 찾았으면 값을 설정하고
                // 스택을 저장한다.
                found.Value = value;
                RootNode    = SaveStack(k, stack);
                return;
            }

            // 노드를 추가한다.
            RootNode = InsertNode(k, value, keyRemainder, stack);
        }
Beispiel #12
0
        // 스택을 정리한다.
        protected TrieNode SaveStack(TrieKey key, Stack <TrieNode> stack)
        {
            TrieNode root = null;
            TrieKey  k    = key.Clone();

            while (stack.Count > 0)
            {
                TrieNode node = stack.Pop();

                if (node.Type == NodeType.ValueNode)
                {
                    k.Pop(node.Key.Length);
                }
                else if (node.Type == NodeType.ShortNode)
                {
                    k.Pop(node.Key.Length);
                    if (null != root)
                    {
                        node.Next = root;
                    }
                }
                else if (node.Type == NodeType.FullNode)
                {
                    if (null != root)
                    {
                        Guard.Assert(!k.Empty);
                        node.SetChild(k.Pop(), root);
                    }
                }

                // 노드 RLP 인코딩
                root = node.EncodeRLP();
            }

            return(root);
        }
Beispiel #13
0
 public void Push(TrieKey key)
 {
     Path = Path.Append(key?.Path);
 }
Beispiel #14
0
        // 일치하는 키를 구한다.
        public TrieKey GetMatchKey(TrieKey key)
        {
            int count = Compare(key);

            return(Take(count));
        }
Beispiel #15
0
 public TrieKey(TrieKey other)
 {
     Path    = other.Path.ToArray();
     HasTerm = other.HasTerm;
 }
Beispiel #16
0
        // keyRemainder는 Empty일 수 있다.
        // key는 Empty일 수 없다.
        // stack은 0보다 크다
        protected TrieNode InsertNode(TrieKey key, byte[] value, TrieKey keyRemainder, Stack <TrieNode> stack)
        {
            Guard.Assert(!key.Empty);
            Guard.Assert(stack.Count > 0);

            // 스택의 최종 노드
            TrieNode node = stack.Pop();

            // 최종 노드가 브랜치 노드인 경우
            if (node.Type == NodeType.FullNode)
            {
                stack.Push(node);

                // 브랜치 노드의 자식 노드로 새로운 리프 노드 추가
                // keyRemainder is not empty always
                stack.Push(new TrieNode(this, keyRemainder.Skip(1), value));
            }
            else
            {
                TrieKey  nodeKey  = node.Key;
                TrieNode fullNode = new TrieNode(this);

                int matchingLength = keyRemainder.Compare(nodeKey);
                if (matchingLength > 0)
                {
                    // 공유키로 익스텐션 노드 생성
                    TrieKey sharedKey = new TrieKey(keyRemainder.Take(matchingLength).Path, false);
                    stack.Push(new TrieNode(this, sharedKey, fullNode));

                    nodeKey      = nodeKey.Skip(matchingLength);
                    keyRemainder = keyRemainder.Skip(matchingLength);
                }

                // 스택에 브랜치 노드 추가
                stack.Push(fullNode);

                // 기존 노드
                if (!nodeKey.Empty)
                {
                    Nibble branchKey = nodeKey.PopFront();
                    if (nodeKey.Empty && node.Type == NodeType.ShortNode)
                    {
                        // replace extension node to branch node
                        var child = node.Next;
                        fullNode.SetChild(branchKey, child.EncodeRLP());
                    }
                    else
                    {
                        node.Key = nodeKey;
                        fullNode.SetChild(branchKey, node.EncodeRLP());
                    }
                }
                else
                {
                    Guard.Assert(node.Type == NodeType.ValueNode);

                    // 브랜치 노드에 값 설정
                    fullNode.Value = node.Value;
                }

                // 스택에 새로운 리프 노드를 추가한다.
                // 만약, 잔여 키가 비어있으면 브랜치 노드에 값 설정한다.
                if (keyRemainder.Empty)
                {
                    fullNode.Value = value;
                }
                else
                {
                    stack.Push(new TrieNode(this, keyRemainder.Skip(1), value));
                }
            }

            return(SaveStack(key, stack));
        }
Beispiel #17
0
        // 루트 부터 key에 해당하는 경로를 탐색하여
        // 일치하는 노드, 잔여 경로, 노드 스택(경로에 해당하는) 을 구한다.
        protected (TrieNode found, TrieKey keyRemainder, Stack <TrieNode> stack) FindNode(TrieNode root, TrieKey key)
        {
            if (ReferenceEquals(root, null))
            {
                throw new ArgumentNullException(nameof(root));
            }
            if (ReferenceEquals(key, null) || key.Empty)
            {
                throw new ArgumentNullException(nameof(key));
            }

            // 노드 경로 스택
            Stack <TrieNode> stack = new Stack <TrieNode>();

            // 노드와 검색 경로
            TrieNode node         = root;
            TrieKey  keyRemainder = key.Clone();

            while (node != null && node.Type != NodeType.EmptyNode)
            {
                // 노드 스택에 노드 추가
                stack.Push(node);

                // 현재 노드가 브랜치 노드이면
                if (node.Type == NodeType.FullNode)
                {
                    // 브랜치 노드에서 경로가 종료되면 탐색 종료
                    if (keyRemainder.Empty)
                    {
                        return(node, TrieKey.EmptyKey, stack);
                    }

                    // 경로에 해당하는 자식 노드가 없으면 탐색 종료
                    Nibble   radix = keyRemainder[0];
                    TrieNode child = node.GetChild(radix);
                    if (child == null)
                    {
                        return(null, keyRemainder, stack);
                    }

                    // 자식 노드로 탐색 계속 진행
                    node = child;
                    keyRemainder.PopFront();
                    continue;
                }

                // 현재 노드가 익스텐션 노드이면
                if (node.Type == NodeType.ShortNode)
                {
                    // 노드 키 ( 항상 키가 존재해야 한다 )
                    TrieKey k = node.Key;
                    Guard.Assert(!k.Empty);

                    // 익스텐션 키가 일치하지 않으면 탐색 종료
                    int matchingLength = keyRemainder.Compare(k);
                    if (matchingLength != k.Length)
                    {
                        return(null, keyRemainder, stack);
                    }

                    // 익스텐션 노드의 자식 노드로 계속 탐색 진행
                    //keyRemainder.PopFront(k.Length);
                    keyRemainder = keyRemainder.Skip(k.Length);
                    node         = node.Next;
                    continue;
                }

                // 리프 노드
                return(keyRemainder == node.Key ? (node, TrieKey.EmptyKey, stack) : (null, keyRemainder, stack));
            }

            throw new Exception("wtf!");
        }
Beispiel #18
0
        // RLP를 디코딩하여 노드 상태를 완전하게 만든다.
        internal TrieNode DecodeRLP()
        {
            if (ReferenceEquals(rlp, null))
            {
                throw new Exception("can't decode empty rlp");
            }

            if (!Parsed)
            {
                var rlp = new RlpDecoder(this.rlp);

                if (Type == NodeType.FullNode)
                {
                    if (rlp.Count != 17)
                    {
                        throw new Exception("can't decode rlp for full node");
                    }

                    // child node
                    chidrens = new TrieNode[16];
                    for (int i = 0; i < 16; i++)
                    {
                        byte[] node = trie.Read(rlp[i].Value);
                        chidrens[i] = node != null ? new TrieNode(trie, node) : null;
                    }

                    // value
                    value = rlp[16].Value;
                }
                else if (Type == NodeType.ShortNode)
                {
                    if (rlp.Count != 2)
                    {
                        throw new Exception("can't decode rlp for short node");
                    }

                    // key
                    key = TrieKey.Decode(rlp[0].Value);

                    // next node
                    byte[] node = trie.Read(rlp[1].Value);
                    next = node != null ? new TrieNode(trie, node) : null;
                }
                else if (Type == NodeType.ValueNode)
                {
                    if (rlp.Count != 2)
                    {
                        throw new Exception("can't decode rlp for value node");
                    }

                    // key
                    key = TrieKey.Decode(rlp[0].Value);

                    // value
                    value = rlp[1].Value;
                }
                else
                {
                    throw new Exception("can't decoded rlp for unknown node type");
                }

                Parsed = true;
            }

            return(this);
        }
Beispiel #19
0
 public int Compare(TrieKey key)
 {
     return(!ReferenceEquals(key, null) ? CountMatchingNibbleLength(Path, key.Path) : 0);
 }