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