Exemple #1
0
    def _normalize_branch_node(self, node):
        """
        A branch node which is left with only a single non-blank item should be
        turned into either a leaf or extension node.
        """
        iter_node = iter(node)
        if any(iter_node) and any(iter_node):
            return node

        if node[16]:
            return [compute_leaf_key([]), node[16]]

        sub_node_idx, sub_node_hash = next(
            (idx, v) for idx, v in enumerate(node[:16]) if v)
        sub_node = self.get_node(sub_node_hash)
        sub_node_type = get_node_type(sub_node)

        self._prune_node(sub_node)

        if sub_node_type in {NODE_TYPE_LEAF, NODE_TYPE_EXTENSION}:
            new_subnode_key = encode_nibbles(
                tuple(
                    itertools.chain(
                        [sub_node_idx],
                        decode_nibbles(sub_node[0]),
                    )))
            return [new_subnode_key, sub_node[1]]
        elif sub_node_type == NODE_TYPE_BRANCH:
            subnode_hash = self._persist_node(sub_node)
            return [encode_nibbles([sub_node_idx]), subnode_hash]
        else:
            raise Exception("Invariant: this code block should be unreachable")
Exemple #2
0
 def deserialize(cls, encoded: bytes) -> 'HexaryTrieFog':
     serial_prefix = b'HexaryTrieFog:'
     if not encoded.startswith(serial_prefix):
         raise ValueError(f"Cannot deserialize this into HexaryTrieFog object: {encoded!r}")
     else:
         encoded_list = encoded[len(serial_prefix):]
         prefix_list = ast.literal_eval(encoded_list.decode())
         deserialized_prefixes = SortedSet(
             # decode nibbles from compressed bytes value, and validate each value in range(16)
             Nibbles(decode_nibbles(prefix))
             for prefix in prefix_list
         )
         return cls._new_trie_fog(deserialized_prefixes)
Exemple #3
0
 def get_node_type(node):
     if node == BLANK_NODE:
         return NODE_TYPE_BLANK
     elif len(node) == 2:
         key, _ = node
         nibbles = decode_nibbles(key)
         if is_nibbles_terminated(nibbles):
             return NODE_TYPE_LEAF
         else:
             return NODE_TYPE_EXTENSION
     elif len(node) == 17:
         return NODE_TYPE_BRANCH
     else:
         raise InvalidNode("Unable to determine node type")
Exemple #4
0
    def _delete_kv_node(self, node, trie_key):
        current_key = extract_key(node)

        if not key_starts_with(trie_key, current_key):
            # key not present?....
            return node

        node_type = get_node_type(node)

        if node_type == NODE_TYPE_LEAF:
            if trie_key == current_key:
                return BLANK_NODE
            else:
                return node

        sub_node_key = trie_key[len(current_key):]
        sub_node = self.get_node(node[1])

        new_sub_node = self._delete(sub_node, sub_node_key)
        encoded_new_sub_node = self._persist_node(new_sub_node)

        if encoded_new_sub_node == node[1]:
            return node

        if new_sub_node == BLANK_NODE:
            return BLANK_NODE

        new_sub_node_type = get_node_type(new_sub_node)
        if new_sub_node_type in {NODE_TYPE_LEAF, NODE_TYPE_EXTENSION}:
            self._prune_node(new_sub_node)

            new_key = current_key + decode_nibbles(new_sub_node[0])
            return [encode_nibbles(new_key), new_sub_node[1]]

        if new_sub_node_type == NODE_TYPE_BRANCH:
            return [encode_nibbles(current_key), encoded_new_sub_node]

        raise Exception("Invariant, this code path should not be reachable")