github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/validator/sawtooth_validator/state/merkle.py (about) 1 # Copyright 2016 Intel Corporation 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 # ------------------------------------------------------------------------------ 15 16 import ctypes 17 from enum import IntEnum 18 19 import cbor 20 21 from sawtooth_validator import ffi 22 23 24 # This is included for legacy reasons. 25 INIT_ROOT_KEY = '' 26 27 28 def _decode(encoded): 29 return cbor.loads(encoded) 30 31 32 def _encode(value): 33 return cbor.dumps(value, sort_keys=True) 34 35 36 class MerkleDatabase(ffi.OwnedPointer): 37 38 def __init__(self, database, merkle_root=None): 39 super(MerkleDatabase, self).__init__('merkle_db_drop') 40 41 if merkle_root: 42 init_root = ctypes.c_char_p(merkle_root.encode()) 43 _libexec('merkle_db_new_with_root', database.pointer, 44 init_root, ctypes.byref(self.pointer)) 45 else: 46 _libexec('merkle_db_new', database.pointer, 47 ctypes.byref(self.pointer)) 48 49 @staticmethod 50 def create_index_configuration(): 51 return ['change_log', 'duplicate_log'] 52 53 def __iter__(self): 54 return self.leaves() 55 56 def __contains__(self, item): 57 """Does the tree contain an address. 58 59 Args: 60 item (str): An address. 61 62 Returns: 63 (bool): True if it does contain, False otherwise. 64 """ 65 try: 66 _libexec('merkle_db_contains', self.pointer, 67 item.encode()) 68 # No error implies found 69 return True 70 except KeyError: 71 return False 72 73 @staticmethod 74 def prune(database, merkle_root): 75 c_root_hash = ctypes.c_char_p(merkle_root.encode()) 76 c_result = ctypes.c_bool() 77 _libexec('merkle_db_prune', database.pointer, c_root_hash, 78 ctypes.byref(c_result)) 79 80 return c_result.value 81 82 def get_merkle_root(self): 83 (c_merkle_root, c_merkle_root_len) = ffi.prepare_byte_result() 84 _libexec('merkle_db_get_merkle_root', self.pointer, 85 ctypes.byref(c_merkle_root), ctypes.byref(c_merkle_root_len)) 86 87 return ffi.from_c_bytes( 88 c_merkle_root, c_merkle_root_len).decode() 89 90 def set_merkle_root(self, merkle_root): 91 c_root = ctypes.c_char_p(merkle_root.encode()) 92 _libexec('merkle_db_set_merkle_root', self.pointer, c_root) 93 94 def __getitem__(self, address): 95 return self.get(address) 96 97 def get(self, address): 98 c_address = ctypes.c_char_p(address.encode()) 99 (c_data, c_data_len) = ffi.prepare_byte_result() 100 101 _libexec('merkle_db_get', self.pointer, c_address, 102 ctypes.byref(c_data), ctypes.byref(c_data_len)) 103 104 return _decode(ffi.from_c_bytes(c_data, c_data_len)) 105 106 def __setitem__(self, address, value): 107 return self.set(address, value) 108 109 def set(self, address, value): 110 c_address = ctypes.c_char_p(address.encode()) 111 112 (c_merkle_root, c_merkle_root_len) = ffi.prepare_byte_result() 113 114 data = _encode(value) 115 _libexec('merkle_db_set', self.pointer, c_address, 116 data, len(data), 117 ctypes.byref(c_merkle_root), 118 ctypes.byref(c_merkle_root_len)) 119 120 return ffi.from_c_bytes( 121 c_merkle_root, c_merkle_root_len).decode() 122 123 def delete(self, address): 124 c_address = ctypes.c_char_p(address.encode()) 125 (c_merkle_root, c_merkle_root_len) = ffi.prepare_byte_result() 126 _libexec('merkle_db_delete', self.pointer, c_address, 127 ctypes.byref(c_merkle_root), 128 ctypes.byref(c_merkle_root_len)) 129 130 return ffi.from_c_bytes( 131 c_merkle_root, c_merkle_root_len).decode() 132 133 def update(self, set_items, delete_items=None, virtual=True): 134 """ 135 136 Args: 137 set_items (dict): dict key, values where keys are addresses 138 delete_items (list): list of addresses 139 virtual (boolean): True if not committing to disk. I.e., 140 speculative root hash 141 Returns: 142 the state root after the operations 143 """ 144 c_set_items = (ctypes.POINTER(_Entry) * len(set_items))() 145 for (i, (key, value)) in enumerate(set_items.items()): 146 c_set_items[i] = ctypes.pointer(_Entry.new(key, _encode(value))) 147 148 if delete_items is None: 149 delete_items = [] 150 151 c_delete_items = (ctypes.c_char_p * len(delete_items))() 152 for (i, address) in enumerate(delete_items): 153 c_delete_items[i] = ctypes.c_char_p(address.encode()) 154 155 (c_merkle_root, c_merkle_root_len) = ffi.prepare_byte_result() 156 _libexec('merkle_db_update', self.pointer, 157 c_set_items, ctypes.c_size_t(len(set_items)), 158 c_delete_items, ctypes.c_size_t(len(delete_items)), 159 virtual, 160 ctypes.byref(c_merkle_root), 161 ctypes.byref(c_merkle_root_len)) 162 163 return ffi.from_c_bytes( 164 c_merkle_root, c_merkle_root_len).decode() 165 166 def addresses(self): 167 addresses = [] 168 for address, _ in self: 169 addresses.append(address) 170 171 return addresses 172 173 def leaves(self, prefix=None): 174 """Returns an iterator which returns tuples of (address, data) values 175 """ 176 try: 177 return _LeafIterator(self.pointer, prefix) 178 except KeyError: 179 # The prefix doesn't exist 180 return iter([]) 181 182 def close(self): 183 pass 184 185 186 def _libexec(name, *args): 187 res = ffi.LIBRARY.call(name, *args) 188 if res == ErrorCode.Success: 189 return 190 elif res == ErrorCode.NullPointerProvided: 191 raise TypeError("Provided null pointer(s)") 192 elif res == ErrorCode.NotFound: 193 raise KeyError("Value was not found") 194 elif res == ErrorCode.DatabaseError: 195 raise ValueError("A Database Error occurred") 196 elif res == ErrorCode.InvalidHashString: 197 raise KeyError( 198 "merkle root was not a valid hash") 199 elif res == ErrorCode.InvalidAddress: 200 raise KeyError( 201 "Address was not valid ") 202 elif res == ErrorCode.InvalidChangeLogIndex: 203 raise ValueError("The Change Log index is in an invalid state") 204 elif res == ErrorCode.StopIteration: 205 raise StopIteration() 206 elif res == ErrorCode.Unknown: 207 raise ValueError("An unknown error occurred") 208 else: 209 raise ValueError("An unknown error occurred: {}".format(res)) 210 211 212 class _LeafIterator: 213 def __init__(self, merkle_db_ptr, prefix=None): 214 if prefix is None: 215 prefix = '' 216 217 c_prefix = ctypes.c_char_p(prefix.encode()) 218 219 self._c_iter_ptr = ctypes.c_void_p() 220 221 _libexec('merkle_db_leaf_iterator_new', 222 merkle_db_ptr, c_prefix, ctypes.byref(self._c_iter_ptr)) 223 224 def __del__(self): 225 if self._c_iter_ptr: 226 _libexec('merkle_db_leaf_iterator_drop', self._c_iter_ptr) 227 self._c_iter_ptr = None 228 229 def __iter__(self): 230 return self 231 232 def __next__(self): 233 if not self._c_iter_ptr: 234 raise StopIteration() 235 236 (c_address, c_address_len) = ffi.prepare_byte_result() 237 (c_value, c_value_len) = ffi.prepare_byte_result() 238 239 _libexec('merkle_db_leaf_iterator_next', self._c_iter_ptr, 240 ctypes.byref(c_address), 241 ctypes.byref(c_address_len), 242 ctypes.byref(c_value), 243 ctypes.byref(c_value_len)) 244 245 address = ffi.from_c_bytes(c_address, c_address_len).decode() 246 value = _decode(ffi.from_c_bytes(c_value, c_value_len)) 247 248 return (address, value) 249 250 251 class _Entry(ctypes.Structure): 252 _fields_ = [('address', ctypes.c_char_p), 253 ('data', ctypes.c_char_p), 254 ('data_len', ctypes.c_size_t)] 255 256 @staticmethod 257 def new(address, data): 258 return _Entry( 259 ctypes.c_char_p(address.encode()), 260 data, 261 len(data) 262 ) 263 264 265 class ErrorCode(IntEnum): 266 Success = ffi.CommonErrorCode.Success 267 # Input errors 268 NullPointerProvided = ffi.CommonErrorCode.NullPointerProvided 269 InvalidHashString = 2 270 InvalidAddress = 3 271 272 # output errors 273 DatabaseError = 0x11 274 NotFound = 0x12 275 InvalidChangeLogIndex = 0x13 276 277 StopIteration = 0xF0 278 Unknown = 0xFF