예제 #1
0
    def _iter_branch(self, node):
        """yield (key, value) stored in this and the descendant nodes
        :param node: node in form of list, or BLANK_NODE

        .. note::
            Here key is in full form, rather than key of the individual node
        """
        if node == BLANK_NODE:
            raise StopIteration

        node_type = self._get_node_type(node)

        if is_key_value_type(node_type):
            nibbles = key_nibbles_from_key_value_node(node)
            key = b'+'.join([to_string(x) for x in nibbles])
            if node_type == NODE_TYPE_EXTENSION:
                sub_tree = self._iter_branch(self._get_inner_node_from_extension(node))
            else:
                sub_tree = [(to_string(NIBBLE_TERMINATOR), node[1])]

            # prepend key of this node to the keys of children
            for sub_key, sub_value in sub_tree:
                full_key = (key + b'+' + sub_key).strip(b'+')
                yield (full_key, sub_value)

        elif node_type == NODE_TYPE_BRANCH:
            for i in range(16):
                sub_tree = self._iter_branch(self._decode_to_node(node[i]))
                for sub_key, sub_value in sub_tree:
                    full_key = (str_to_bytes(str(i)) +
                                b'+' + sub_key).strip(b'+')
                    yield (full_key, sub_value)
            if node[16]:
                yield (to_string(NIBBLE_TERMINATOR), node[-1])
예제 #2
0
    def _iter_branch(self, node):
        """yield (key, value) stored in this and the descendant nodes
        :param node: node in form of list, or BLANK_NODE

        .. note::
            Here key is in full form, rather than key of the individual node
        """
        if node == BLANK_NODE:
            raise StopIteration

        node_type = self._get_node_type(node)

        if is_key_value_type(node_type):
            nibbles = without_terminator(unpack_to_nibbles(node[0]))
            key = b'+'.join([to_string(x) for x in nibbles])
            if node_type == NODE_TYPE_EXTENSION:
                sub_tree = self._iter_branch(self._decode_to_node(node[1]))
            else:
                sub_tree = [(to_string(NIBBLE_TERMINATOR), node[1])]

            # prepend key of this node to the keys of children
            for sub_key, sub_value in sub_tree:
                full_key = (key + b'+' + sub_key).strip(b'+')
                yield (full_key, sub_value)

        elif node_type == NODE_TYPE_BRANCH:
            for i in range(16):
                sub_tree = self._iter_branch(self._decode_to_node(node[i]))
                for sub_key, sub_value in sub_tree:
                    full_key = (str_to_bytes(str(i)) + b'+' +
                                sub_key).strip(b'+')
                    yield (full_key, sub_value)
            if node[16]:
                yield (to_string(NIBBLE_TERMINATOR), node[-1])
예제 #3
0
def test_get_prefix_nodes():
    trie = Trie(PersistentDB(KeyValueStorageInMemory()))
    prefix = 'abcd'
    prefix_nibbles = bin_to_nibbles(to_string(prefix))
    key1 = prefix + '1'
    key2 = prefix + '2'
    key3 = prefix + '3'
    trie.update(key1.encode(), rlp_encode(['v1']))
    last_node = trie._get_last_node_for_prfx(trie.root_node, prefix_nibbles)
    # The last node should be a leaf since only 1 key
    assert trie._get_node_type(last_node) == NODE_TYPE_LEAF

    # The queried key is larger than prefix, results in blank node
    last_node_ = trie._get_last_node_for_prfx(
        trie.root_node, bin_to_nibbles(to_string(prefix + '5')))
    assert last_node_ == BLANK_NODE

    trie.update(key2.encode(), rlp_encode(['v2']))
    last_node = trie._get_last_node_for_prfx(trie.root_node, prefix_nibbles)
    # The last node should be an extension since more than 1 key
    assert trie._get_node_type(last_node) == NODE_TYPE_EXTENSION

    trie.update(key3.encode(), rlp_encode(['v3']))
    last_node = trie._get_last_node_for_prfx(trie.root_node, prefix_nibbles)
    assert trie._get_node_type(last_node) == NODE_TYPE_EXTENSION

    last_node_key = without_terminator(unpack_to_nibbles(last_node[0]))
    # Key for the fetched prefix nodes (ignore last nibble) is same as prefix nibbles
    assert last_node_key[:-1] == prefix_nibbles

    # The extension node is correctly decoded.
    decoded_extension = trie._decode_to_node(last_node[1])
    assert decoded_extension[1] == [b' ', rlp_encode(['v1'])]
    assert decoded_extension[2] == [b' ', rlp_encode(['v2'])]
    assert decoded_extension[3] == [b' ', rlp_encode(['v3'])]
예제 #4
0
 def produce_spv_proof_for_keys_with_prefix(self,
                                            key_prfx,
                                            root=None,
                                            get_value=False):
     # Return a proof for keys in the trie with the given prefix.
     root = root if root is not None else self.root_node
     proof.push(RECORDING)
     seen_prfx = []
     prefix_node = self._get_last_node_for_prfx(root,
                                                bin_to_nibbles(
                                                    to_string(key_prfx)),
                                                seen_prfx=seen_prfx)
     # The next line traverses the prefix node and the children of the
     # prefix node. Needed for generating the proof and the values
     rv = self._to_dict(prefix_node)
     # If values are needed then convert the keys appropriately
     if get_value:
         new_rv = {}
         for k, v in rv.items():
             # Add the seen prefix to each key
             k_ = seen_prfx + [int(x) for x in k.split(b'+')]
             new_rv[nibbles_to_bin(without_terminator_and_flags(k_))] = v
         rv = new_rv
     o = proof.get_nodelist()
     proof.pop()
     return (o, rv) if get_value else o
예제 #5
0
 def get_at(self, root_node, key):
     """
     Get value of a key when the root node was `root_node`
     :param root_node:
     :param key:
     :return:
     """
     return self._get(root_node, bin_to_nibbles(to_string(key)))
예제 #6
0
 def get(self, key: bytes, isCommitted: bool = True) -> Optional[bytes]:
     if not isCommitted:
         val = self._trie.get(key)
     else:
         val = self._trie._get(self.committedHead,
                               bin_to_nibbles(to_string(key)))
     if val:
         return self.get_decoded(val)
예제 #7
0
 def get(self, key: bytes, isCommitted: bool = True):
     if not isCommitted:
         val = self._trie.get(key)
     else:
         val = self._trie._get(self.committedHead,
                               bin_to_nibbles(to_string(key)))
     if val:
         return rlp_decode(val)[0]
예제 #8
0
 def get_at(self, root_node, key):
     """
     Get value of a key when the root node was `root_node`
     :param root_node:
     :param key:
     :return:
     """
     return self._get(root_node, bin_to_nibbles(to_string(key)))
예제 #9
0
 def get(self, key: bytes, isCommitted: bool = True) -> Optional[bytes]:
     if not isCommitted:
         val = self._trie.get(key)
     else:
         val = self._trie._get(self.committedHead,
                               bin_to_nibbles(to_string(key)))
     if val:
         return self.get_decoded(val)
예제 #10
0
 def produce_spv_proof_for_nodes_with_key_prfx(self, key_prfx, root=None):
     # Return a proof for keys in the trie with the given prefix.
     root = root or self.root_node
     proof.push(RECORDING)
     prefix_node = self._get_last_node_for_prfx(root, bin_to_nibbles(to_string(key_prfx)))
     list(self._iter_branch(prefix_node))
     o = proof.get_nodelist()
     proof.pop()
     return o
예제 #11
0
    def _to_dict(self, node):
        '''convert (key, value) stored in this and the descendant nodes
        to dict items.

        :param node: node in form of list, or BLANK_NODE

        .. note::

            Here key is in full form, rather than key of the individual node
        '''
        if node == BLANK_NODE:
            return {}

        node_type = self._get_node_type(node)

        if is_key_value_type(node_type):
            nibbles = key_nibbles_from_key_value_node(node)
            key = b'+'.join([to_string(x) for x in nibbles])
            if node_type == NODE_TYPE_EXTENSION:
                sub_dict = self._to_dict(
                    self._get_inner_node_from_extension(node))
            else:
                sub_dict = {to_string(NIBBLE_TERMINATOR): node[1]}

            # prepend key of this node to the keys of children
            res = {}
            for sub_key, sub_value in sub_dict.items():
                full_key = (key + b'+' + sub_key).strip(b'+')
                res[full_key] = sub_value
            return res

        elif node_type == NODE_TYPE_BRANCH:
            res = {}
            for i in range(16):
                sub_dict = self._to_dict(self._decode_to_node(node[i]))

                for sub_key, sub_value in sub_dict.items():
                    full_key = (str_to_bytes(str(i)) + b'+' +
                                sub_key).strip(b'+')
                    res[full_key] = sub_value

            if node[16]:
                res[to_string(NIBBLE_TERMINATOR)] = node[-1]
            return res
예제 #12
0
    def _to_dict(self, node):
        '''convert (key, value) stored in this and the descendant nodes
        to dict items.

        :param node: node in form of list, or BLANK_NODE

        .. note::

            Here key is in full form, rather than key of the individual node
        '''
        if node == BLANK_NODE:
            return {}

        node_type = self._get_node_type(node)

        if is_key_value_type(node_type):
            nibbles = key_nibbles_from_key_value_node(node)
            key = b'+'.join([to_string(x) for x in nibbles])
            if node_type == NODE_TYPE_EXTENSION:
                sub_dict = self._to_dict(self._get_inner_node_from_extension(node))
            else:
                sub_dict = {to_string(NIBBLE_TERMINATOR): node[1]}

            # prepend key of this node to the keys of children
            res = {}
            for sub_key, sub_value in sub_dict.items():
                full_key = (key + b'+' + sub_key).strip(b'+')
                res[full_key] = sub_value
            return res

        elif node_type == NODE_TYPE_BRANCH:
            res = {}
            for i in range(16):
                sub_dict = self._to_dict(self._decode_to_node(node[i]))

                for sub_key, sub_value in sub_dict.items():
                    full_key = (str_to_bytes(str(i)) +
                                b'+' + sub_key).strip(b'+')
                    res[full_key] = sub_value

            if node[16]:
                res[to_string(NIBBLE_TERMINATOR)] = node[-1]
            return res
예제 #13
0
    def update(self, key, value):
        '''
        :param key: a string
        :value: a string
        '''
        if not is_string(key):
            raise Exception("Key must be string")

        # if len(key) > 32:
        #     raise Exception("Max key length is 32")

        if not is_string(value):
            raise Exception("Value must be string")

        # if value == '':
        #     return self.delete(key)
        old_root = copy.deepcopy(self.root_node)
        self.root_node = self._update_and_delete_storage(
            self.root_node, bin_to_nibbles(to_string(key)), to_string(value))
        self.replace_root_hash(old_root, self.root_node)
예제 #14
0
    def update(self, key, value):
        '''
        :param key: a string
        :value: a string
        '''
        if not is_string(key):
            raise Exception("Key must be string")

        # if len(key) > 32:
        #     raise Exception("Max key length is 32")

        if not is_string(value):
            raise Exception("Value must be string")

        # if value == '':
        #     return self.delete(key)
        old_root = copy.deepcopy(self.root_node)
        self.root_node = self._update_and_delete_storage(
            self.root_node,
            bin_to_nibbles(to_string(key)),
            to_string(value))
        self.replace_root_hash(old_root, self.root_node)
예제 #15
0
    def delete(self, key):
        '''
        :param key: a string with length of [0, 32]
        '''
        if not is_string(key):
            raise Exception("Key must be string")

        if len(key) > 32:
            raise Exception("Max key length is 32")

        old_root = copy.deepcopy(self.root_node)
        self.root_node = self._delete_and_delete_storage(
            self.root_node, bin_to_nibbles(to_string(key)))
        self.replace_root_hash(old_root, self.root_node)
예제 #16
0
    def delete(self, key):
        '''
        :param key: a string with length of [0, 32]
        '''
        if not is_string(key):
            raise Exception("Key must be string")

        if len(key) > 32:
            raise Exception("Max key length is 32")

        old_root = copy.deepcopy(self.root_node)
        self.root_node = self._delete_and_delete_storage(
            self.root_node,
            bin_to_nibbles(to_string(key)))
        self.replace_root_hash(old_root, self.root_node)
예제 #17
0
 def produce_spv_proof_for_keys_with_prefix(self, key_prfx, root=None, get_value=False):
     # Return a proof for keys in the trie with the given prefix.
     root = root or self.root_node
     proof.push(RECORDING)
     seen_prfx = []
     prefix_node = self._get_last_node_for_prfx(root,
                                                bin_to_nibbles(to_string(key_prfx)),
                                                seen_prfx=seen_prfx)
     # The next line traverses the prefix node and the children of the
     # prefix node. Needed for generating the proof and the values
     rv = self._to_dict(prefix_node)
     # If values are needed then convert the keys appropriately
     if get_value:
         new_rv = {}
         for k, v in rv.items():
             # Add the seen prefix to each key
             k_ = seen_prfx + [int(x) for x in k.split(b'+')]
             new_rv[nibbles_to_bin(without_terminator_and_flags(k_))] = v
         rv = new_rv
     o = proof.get_nodelist()
     proof.pop()
     return (o, rv) if get_value else o
예제 #18
0
 def get_for_root_hash(self, root_hash, key: bytes) -> Optional[bytes]:
     root = self._hash_to_node(root_hash)
     val = self._trie._get(root,
                           bin_to_nibbles(to_string(key)))
     if val:
         return self.get_decoded(val)
예제 #19
0
 def get_for_root_hash(self, root_hash, key: bytes) -> Optional[bytes]:
     root = self._hash_to_node(root_hash)
     val = self._trie._get(root, bin_to_nibbles(to_string(key)))
     if val:
         return self.get_decoded(val)
예제 #20
0
 def get(self, key):
     return self._get(self.root_node, bin_to_nibbles(to_string(key)))
예제 #21
0
 def get(self, key):
     return self._get(self.root_node, bin_to_nibbles(to_string(key)))