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
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)
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)
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
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
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)