예제 #1
0
    def get(self, encoded_key):
        """
        This method gets a value associtated with provided key.

        Note: this method does not RLP-encode the key. If you use encoded keys, you should encode it yourself.

        Parameters
        ----------
        encoded_key: bytes
            RLP-encoded key.

        Returns
        -------
        bytes
            Stored value associated with provided key.

        Raises
        ------
        KeyError
            KeyError is raised if there is no value assotiated with provided key.
        """
        if not self._root:
            raise KeyError

        if self._secure:
            encoded_key = keccak_hash(encoded_key)

        path = NibblePath(encoded_key)

        result_node = self._get(self._root, path)

        return result_node.data
예제 #2
0
    def root_hash(self):
        """ Returns a hash of the trie's root node. For empty trie it's the hash of the RLP-encoded empty string. """

        if not self._root:
            return Node.EMPTY_HASH
        elif len(self._root) == 32:
            return self._root
        else:
            return keccak_hash(self._root)
예제 #3
0
    def into_reference(node):
        """
        Returns reference to the given node.

        If length of encoded node is less than 32 bytes, the reference is encoded node itseld (In-place reference).
        Otherwise reference is keccak hash of encoded node.
        """
        encoded_node = node.encode()
        if len(encoded_node) < 32:
            return encoded_node
        else:
            return keccak_hash(encoded_node)
예제 #4
0
    def update(self, encoded_key, encoded_value):
        """
        This method updates a provided key-value pair into the trie.

        If there is no such a key in the trie, a new entry will be created.
        Otherwise value associtaed with key is updated.
        Note: this method does not RLP-encode neither key or value. If you use encoded keys,
        you should encode it yourself.

        Parameters
        ----------
        encoded_key: bytes
            RLP-encoded key.
        encoded_value: bytes
            RLP-encoded value.
        """
        if self._secure:
            encoded_key = keccak_hash(encoded_key)

        path = NibblePath(encoded_key)

        result = self._update(self._root, path, encoded_value)

        self._root = result
예제 #5
0
    def delete(self, encoded_key):
        """
        This method removes a value associtated with provided key.

        Note: this method does not RLP-encode the key. If you use encoded keys, you should encode it yourself.

        Parameters
        ----------
        encoded_key: bytes
            RLP-encoded key.

        Raises
        ------
        KeyError
            KeyError is raised if there is no value assotiated with provided key.
        """

        if self._root is None:
            return

        if self._secure:
            encoded_key = keccak_hash(encoded_key)

        path = NibblePath(encoded_key)

        action, info = self._delete(self._root, path)

        if action == MerklePatriciaTrie._DeleteAction.DELETED:
            # Trie is empty
            self._root = None
        elif action == MerklePatriciaTrie._DeleteAction.UPDATED:
            new_root = info
            self._root = new_root
        elif action == MerklePatriciaTrie._DeleteAction.USELESS_BRANCH:
            _, new_root = info
            self._root = new_root
예제 #6
0
class Node:
    EMPTY_HASH = keccak_hash(rlp.encode(b''))

    class Leaf:
        def __init__(self, path, data):
            self.path = path
            self.data = data

        def __str__(self):
            return 'Leaf Node\n Path = {}, Data = {}'.format(
                self.path, self.data)

        def encode(self):
            return rlp.encode([self.path.encode(True), self.data])

    class Extension:
        def __init__(self, path, next_ref):
            self.path = path
            self.next_ref = next_ref

        def __str__(self):
            return 'Extension Node\n Path = {}, Next_Reference = {}'.format(
                self.path, self.next_ref)

        def encode(self):
            next_ref = _prepare_reference_for_encoding(self.next_ref)
            return rlp.encode([self.path.encode(False), next_ref])

    class Branch:
        def __init__(self, branches, data=None):
            self.branches = branches
            self.data = data

        def __str__(self):
            return 'Branch Node \n Branches = {} \n Data = {}'.format(
                self.branches, self.data)

        def encode(self):
            branches = list(map(_prepare_reference_for_encoding,
                                self.branches))
            return rlp.encode(branches + [self.data])

    def decode(encoded_data):
        """ Decodes node from RLP. """
        data = rlp.decode(encoded_data)

        assert len(data) == 17 or len(data) == 2  # TODO throw exception

        if len(data) == 17:
            branches = list(map(_prepare_reference_for_usage, data[:16]))
            node_data = data[16]
            return Node.Branch(branches, node_data)

        path, is_leaf = NibblePath.decode_with_type(data[0])
        if is_leaf:
            return Node.Leaf(path, data[1])
        else:
            ref = _prepare_reference_for_usage(data[1])
            return Node.Extension(path, ref)

    def into_reference(node):
        """
        Returns reference to the given node.

        If length of encoded node is less than 32 bytes, the reference is encoded node itseld (In-place reference).
        Otherwise reference is keccak hash of encoded node.
        """
        encoded_node = node.encode()
        if len(encoded_node) < 32:
            return encoded_node
        else:
            return keccak_hash(encoded_node)