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])
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])
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'])]
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
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)))
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)
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]
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)))
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)
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
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
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
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)
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)
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)
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)
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
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)
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)
def get(self, key): return self._get(self.root_node, bin_to_nibbles(to_string(key)))
def get(self, key): return self._get(self.root_node, bin_to_nibbles(to_string(key)))