github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/validator/tests/test_merkle_trie/tests.py (about)

     1  # Copyright 2017 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 hashlib
    17  import os
    18  import unittest
    19  import random
    20  import shutil
    21  import tempfile
    22  from string import ascii_lowercase
    23  
    24  from sawtooth_validator.state.merkle import MerkleDatabase
    25  from sawtooth_validator.database.native_lmdb import NativeLmdbDatabase
    26  
    27  
    28  class TestSawtoothMerkleTrie(unittest.TestCase):
    29      def setUp(self):
    30          self.dir = tempfile.mkdtemp()
    31          self.file = os.path.join(self.dir, 'merkle.lmdb')
    32  
    33          self.lmdb = NativeLmdbDatabase(
    34              self.file,
    35              indexes=MerkleDatabase.create_index_configuration(),
    36              _size=120 * 1024 * 1024)
    37  
    38          self.trie = MerkleDatabase(self.lmdb)
    39  
    40      def tearDown(self):
    41          self.trie.close()
    42          shutil.rmtree(self.dir)
    43  
    44      def test_merkle_trie_root_advance(self):
    45          value = {'name': 'foo', 'value': 1}
    46  
    47          orig_root = self.get_merkle_root()
    48          new_root = self.set('foo', value)
    49  
    50          self.assert_root(orig_root)
    51          self.assert_no_key('foo')
    52  
    53          self.set_merkle_root(new_root)
    54  
    55          self.assert_root(new_root)
    56          self.assert_value_at_address('foo', value)
    57  
    58      def test_merkle_trie_delete(self):
    59          value = {'name': 'bar', 'value': 1}
    60  
    61          new_root = self.set('bar', value)
    62          self.set_merkle_root(new_root)
    63  
    64          self.assert_root(new_root)
    65          self.assert_value_at_address('bar', value)
    66  
    67          # deleting an invalid key should raise an error
    68          with self.assertRaises(KeyError):
    69              self.delete('barf')
    70  
    71          del_root = self.delete('bar')
    72  
    73          # del_root hasn't been set yet, so address should still have value
    74          self.assert_root(new_root)
    75          self.assert_value_at_address('bar', value)
    76  
    77          self.set_merkle_root(del_root)
    78  
    79          self.assert_root(del_root)
    80          self.assert_no_key('bar')
    81  
    82      def test_merkle_trie_update(self):
    83          init_root = self.get_merkle_root()
    84  
    85          values = {}
    86          key_hashes = {
    87              key: _hash(key)
    88              for key in (_random_string(10) for _ in range(1000))
    89          }
    90  
    91          for key, hashed in key_hashes.items():
    92              value = {key: _random_string(512)}
    93              new_root = self.set(hashed, value, ishash=True)
    94              values[hashed] = value
    95              self.set_merkle_root(new_root)
    96  
    97          self.assert_not_root(init_root)
    98  
    99          for address, value in values.items():
   100              self.assert_value_at_address(
   101                  address, value, ishash=True)
   102  
   103          set_items = {
   104              hashed: {
   105                  key: 5.0
   106              }
   107              for key, hashed in random.sample(key_hashes.items(), 50)
   108          }
   109          values.update(set_items)
   110          delete_items = {
   111              hashed
   112              for hashed in random.sample(list(key_hashes.values()), 50)
   113          }
   114  
   115          # make sure there are no sets and deletes of the same key
   116          delete_items = delete_items - set_items.keys()
   117          for addr in delete_items:
   118              del values[addr]
   119  
   120          virtual_root = self.update(set_items, delete_items, virtual=True)
   121  
   122          # virtual root shouldn't match actual contents of tree
   123          with self.assertRaises(KeyError):
   124              self.set_merkle_root(virtual_root)
   125  
   126          actual_root = self.update(set_items, delete_items, virtual=False)
   127  
   128          # the virtual root should be the same as the actual root
   129          self.assertEqual(virtual_root, actual_root)
   130  
   131          # neither should be the root yet
   132          self.assert_not_root(
   133              virtual_root,
   134              actual_root)
   135  
   136          self.set_merkle_root(actual_root)
   137          self.assert_root(actual_root)
   138  
   139          for address, value in values.items():
   140              self.assert_value_at_address(
   141                  address, value, ishash=True)
   142  
   143          for address in delete_items:
   144              with self.assertRaises(KeyError):
   145                  self.get(address, ishash=True)
   146  
   147      def test_merkle_trie_leaf_iteration(self):
   148          new_root = self.update({
   149              "010101": {"my_data": 1},
   150              "010202": {"my_data": 2},
   151              "010303": {"my_data": 3}
   152          }, [], virtual=False)
   153  
   154          # iterate over the empty trie
   155          iterator = iter(self.trie)
   156          with self.assertRaises(StopIteration):
   157              next(iterator)
   158  
   159          self.set_merkle_root(new_root)
   160  
   161          # Test complete trie iteration
   162          self.assertEqual(
   163              [("010101", {"my_data": 1}),
   164               ("010202", {"my_data": 2}),
   165               ("010303", {"my_data": 3})],
   166              [entry for entry in iter(self.trie)])
   167  
   168          # Test prefixed iteration
   169          self.assertEqual([("010202", {"my_data": 2})],
   170                           [entry for entry in self.trie.leaves('0102')])
   171  
   172      # assertions
   173      def assert_value_at_address(self, address, value, ishash=False):
   174          self.assertEqual(
   175              self.get(address, ishash),
   176              value,
   177              'Wrong value')
   178  
   179      def assert_no_key(self, key):
   180          with self.assertRaises(KeyError):
   181              self.get(key)
   182  
   183      def assert_root(self, expected):
   184          self.assertEqual(
   185              expected,
   186              self.get_merkle_root(),
   187              'Wrong root')
   188  
   189      def assert_not_root(self, *not_roots):
   190          root = self.get_merkle_root()
   191          for not_root in not_roots:
   192              self.assertNotEqual(
   193                  root,
   194                  not_root,
   195                  'Wrong root')
   196  
   197      # trie accessors
   198  
   199      # For convenience, assume keys are not hashed
   200      # unless otherwise indicated.
   201  
   202      def set(self, key, val, ishash=False):
   203          key_ = key if ishash else _hash(key)
   204          return self.trie.set(key_, val)
   205  
   206      def get(self, key, ishash=False):
   207          key_ = key if ishash else _hash(key)
   208          return self.trie.get(key_)
   209  
   210      def delete(self, key, ishash=False):
   211          key_ = key if ishash else _hash(key)
   212          return self.trie.delete(key_)
   213  
   214      def set_merkle_root(self, root):
   215          self.trie.set_merkle_root(root)
   216  
   217      def get_merkle_root(self):
   218          return self.trie.get_merkle_root()
   219  
   220      def update(self, set_items, delete_items=None, virtual=True):
   221          return self.trie.update(set_items, delete_items, virtual=virtual)
   222  
   223  
   224  def _hash(key):
   225      return hashlib.sha512(key.encode()).hexdigest()[:64]
   226  
   227  
   228  def _random_string(length):
   229      return ''.join(random.choice(ascii_lowercase) for _ in range(length))