github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/validator/tests/test_context_manager/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  # pylint: disable=too-many-lines,broad-except
    17  
    18  import unittest
    19  
    20  from collections import namedtuple
    21  import hashlib
    22  import os
    23  import shutil
    24  import tempfile
    25  import time
    26  
    27  from sawtooth_validator.database.native_lmdb import NativeLmdbDatabase
    28  from sawtooth_validator.execution import context_manager
    29  from sawtooth_validator.state.merkle import MerkleDatabase
    30  from sawtooth_validator.protobuf.events_pb2 import Event
    31  
    32  
    33  TestAddresses = namedtuple('TestAddresses',
    34                             ['inputs', 'outputs', 'reads', 'writes'])
    35  
    36  
    37  class TestContextManager(unittest.TestCase):
    38      def __init__(self, test_name):
    39          super().__init__(test_name)
    40          self._temp_dir = None
    41  
    42      def setUp(self):
    43          self._temp_dir = tempfile.mkdtemp()
    44  
    45          self.database_of_record = NativeLmdbDatabase(
    46              os.path.join(self._temp_dir, 'db_of_record.lmdb'),
    47              indexes=MerkleDatabase.create_index_configuration(),
    48              _size=10 * 1024 * 1024)
    49  
    50          self.context_manager = context_manager.ContextManager(
    51              self.database_of_record)
    52          self.first_state_hash = self.context_manager.get_first_root()
    53  
    54          # used for replicating state hash through direct merkle tree updates
    55          self.database_results = NativeLmdbDatabase(
    56              os.path.join(self._temp_dir, 'db_results.lmdb'),
    57              indexes=MerkleDatabase.create_index_configuration(),
    58              _size=10 * 1024 * 1024)
    59  
    60      def tearDown(self):
    61          self.context_manager.stop()
    62          shutil.rmtree(self._temp_dir)
    63  
    64      def _create_address(self, value=None):
    65          """
    66          Args:
    67              value: (str)
    68  
    69          Returns: (str) sha512 of value or random
    70  
    71          """
    72          if value is None:
    73              value = time.time().hex()
    74          return hashlib.sha512(value.encode()).hexdigest()[:70]
    75  
    76      def _setup_context(self):
    77          # 1) Create transaction data
    78          first_transaction = {'inputs': [self._create_address(a) for a in
    79                                          ['aaaa', 'bbbb', 'cccc']],
    80                               'outputs': [self._create_address(a) for a in
    81                                           ['llaa', 'aall', 'nnnn']]}
    82          second_transaction = {
    83              'inputs': [self._create_address(a) for a in
    84                         ['aaaa', 'dddd']],
    85              'outputs': [self._create_address(a) for a in
    86                          ['zzzz', 'yyyy', 'tttt', 'qqqq']]
    87          }
    88          third_transaction = {
    89              'inputs': [self._create_address(a) for a in
    90                         ['eeee', 'dddd', 'ffff']],
    91              'outputs': [self._create_address(a) for a in
    92                          ['oooo', 'oozz', 'zzoo', 'ppoo', 'aeio']]
    93          }
    94          # 2) Create contexts based on that data
    95          context_id_1 = self.context_manager.create_context(
    96              state_hash=self.first_state_hash,
    97              base_contexts=[],
    98              inputs=first_transaction['inputs'],
    99              outputs=first_transaction['outputs'])
   100          context_id_2 = self.context_manager.create_context(
   101              state_hash=self.first_state_hash,
   102              base_contexts=[],
   103              inputs=second_transaction['inputs'],
   104              outputs=second_transaction['outputs'])
   105          context_id_3 = self.context_manager.create_context(
   106              state_hash=self.first_state_hash,
   107              base_contexts=[],
   108              inputs=third_transaction['inputs'],
   109              outputs=third_transaction['outputs'])
   110  
   111          # 3) Set addresses with values
   112          self.context_manager.set(context_id_1, [{self._create_address(a): v}
   113                                                  for a, v in [('llaa', b'1'),
   114                                                               ('aall', b'2'),
   115                                                               ('nnnn', b'3')]])
   116          self.context_manager.set(context_id_2, [{self._create_address(a): v}
   117                                                  for a, v in [('zzzz', b'9'),
   118                                                               ('yyyy', b'11'),
   119                                                               ('tttt', b'12'),
   120                                                               ('qqqq', b'13')]])
   121          self.context_manager.set(context_id_3, [{self._create_address(a): v}
   122                                                  for a, v in [('oooo', b'25'),
   123                                                               ('oozz', b'26'),
   124                                                               ('zzoo', b'27'),
   125                                                               ('ppoo', b'28'),
   126                                                               ('aeio', b'29')]])
   127  
   128          # 4)
   129          context_id = self.context_manager.create_context(
   130              state_hash=self.first_state_hash,
   131              base_contexts=[context_id_1, context_id_2, context_id_3],
   132              inputs=[
   133                  self._create_address(a)
   134                  for a in ['llaa', 'yyyy', 'tttt', 'zzoo']
   135              ],
   136              outputs=[
   137                  self._create_address(a)
   138                  for a in ['llaa', 'yyyy', 'tttt', 'zzoo', 'aeio']
   139              ])
   140          return context_id
   141  
   142      def _create_txn_inputs_outputs(self, start=None):
   143          """Create unique addresses that make up the inputs, outputs,
   144           reads, and writes that are involved in a context.
   145  
   146           Venn Diagram of relationship of disjoint sets that make up the
   147           inputs, outputs, reads, and writes.
   148  
   149           Knowledge of which disjoint set an address is a part of
   150           may give knowledge about a test failure in the context
   151           manager.
   152  
   153                      Inputs                      Outputs
   154              +----------+--------------------------+-----------+
   155              |          |                          |           |
   156              |  i___    |Reads       io__        Writes  _o__  |
   157              |          |                          |           |
   158              |    +-----------+-----------+---------------+    |
   159              |    |     |     |           |        |      |    |
   160              |    |     |     |           |        |      |    |
   161              |    |     |     |           |        |      |    |
   162              |    |     |     |           |        |      |    |
   163              |    |i_r_ | ior_|  iorw     |  io_w  | _o_w |    |
   164              |    |     |     |           |        |      |    |
   165              |    |     |     |           |        |      |    |
   166              |    |     |     |           |        |      |    |
   167              |    +-----------+-----------+---------------+    |
   168              |          |                          |           |
   169              |          |                          |           |
   170              +----------+--------------------------+-----------+
   171  
   172          Args:
   173              start (int): An integer to start the sequence of integers being
   174              hashed to addresses.
   175  
   176          Returns (namedtuple): An object that holds inputs, outputs, reads,
   177              and writes.
   178  
   179          """
   180          if start is None:
   181              start = 0
   182          iorw = [self._create_address(str(i)) for i in range(start, start + 10)]
   183          i_r_ = [
   184              self._create_address(str(i))
   185              for i in range(start + 10, start + 20)
   186          ]
   187          ior_ = [
   188              self._create_address(str(i))
   189              for i in range(start + 20, start + 30)
   190          ]
   191          io__ = [
   192              self._create_address(str(i))
   193              for i in range(start + 30, start + 40)
   194          ]
   195          io_w = [
   196              self._create_address(str(i))
   197              for i in range(start + 40, start + 50)
   198          ]
   199          _o_w = [
   200              self._create_address(str(i))
   201              for i in range(start + 50, start + 60)
   202          ]
   203          _o__ = [
   204              self._create_address(str(i))
   205              for i in range(start + 60, start + 70)
   206          ]
   207          i___ = [
   208              self._create_address(str(i))
   209              for i in range(start + 70, start + 80)
   210          ]
   211          addresses = TestAddresses(
   212              inputs=iorw + ior_ + io__ + io_w + i___,
   213              outputs=ior_ + io__ + io_w + _o__ + _o_w,
   214              reads=i_r_ + ior_,
   215              writes=io_w + _o_w)
   216          return addresses
   217  
   218      def test_execution_results(self):
   219          """Tests that get_execution_results returns the correct values."""
   220          addr1 = self._create_address()
   221          addr2 = self._create_address()
   222          context_id = self.context_manager.create_context(
   223              state_hash=self.context_manager.get_first_root(),
   224              base_contexts=[],
   225              inputs=[addr1, addr2],
   226              outputs=[addr1, addr2])
   227  
   228          sets = {addr1: b'1'}
   229          events = [
   230              Event(
   231                  event_type=teststr,
   232                  attributes=[Event.Attribute(key=teststr, value=teststr)],
   233                  data=teststr.encode()) for teststr in ("test1", "test2")
   234          ]
   235          deletes = {addr2: None}
   236          data = [(teststr.encode()) for teststr in ("test1", "test2")]
   237  
   238          self.context_manager.set(context_id, [sets])
   239          for event in events:
   240              self.context_manager.add_execution_event(context_id, event)
   241  
   242          self.context_manager.delete(context_id, deletes)
   243          for datum in data:
   244              self.context_manager.add_execution_data(
   245                  context_id, datum)
   246  
   247          results = self.context_manager.get_execution_results(context_id)
   248          self.assertEqual(sets, results[0])
   249          self.assertEqual(deletes, results[1])
   250          self.assertEqual(events, results[2])
   251          self.assertEqual(data, results[3])
   252  
   253      def test_address_enforcement(self):
   254          """Tests that the ContextManager enforces address characteristics.
   255  
   256          Notes:
   257              1. Call get and set on the ContextManager with an address that is
   258                 under a namespace, but is an invalid address, and test that
   259                 the methods raise an AuthorizationException.
   260          """
   261  
   262          # 1)
   263          invalid_address1 = 'a' * 69 + 'n'
   264          invalid_address2 = 'b' * 69 + 'y'
   265  
   266          context_id1 = self.context_manager.create_context(
   267              state_hash=self.context_manager.get_first_root(),
   268              base_contexts=[],
   269              inputs=['aaaaaaaa', 'bbbbbbbb'],
   270              outputs=['aaaaaaaa', 'bbbbbbbb'])
   271          with self.assertRaises(context_manager.AuthorizationException):
   272              self.context_manager.get(
   273                  context_id=context_id1,
   274                  address_list=[invalid_address1, invalid_address2])
   275          with self.assertRaises(context_manager.AuthorizationException):
   276              self.context_manager.set(
   277                  context_id=context_id1,
   278                  address_value_list=[{invalid_address1: b'1'},
   279                                      {invalid_address2: b'2'}])
   280  
   281      def test_get_set_wrong_namespace(self):
   282          """Tests that getting and setting from outside the namespace will
   283          raise a AuthorizationException.
   284  
   285          Notes:
   286              1. Assert that sets on a context with addresses that aren't
   287                 under an output namespace raise an AuthorizationException.
   288  
   289              2. Assert that gets on a context with addresses that aren't under
   290                 an input namespace raise an AuthorizationException.
   291          """
   292  
   293          wrong_namespace1 = self._create_address('a')[-10:]
   294          wrong_namespace2 = '00000000'
   295  
   296          ctx_1 = self.context_manager.create_context(
   297              state_hash=self.context_manager.get_first_root(),
   298              base_contexts=[],
   299              inputs=[wrong_namespace1, wrong_namespace2],
   300              outputs=[wrong_namespace1, wrong_namespace2])
   301          # 1
   302          with self.assertRaises(context_manager.AuthorizationException):
   303              self.context_manager.set(
   304                  context_id=ctx_1,
   305                  address_value_list=[{self._create_address('a'): b'1'}])
   306  
   307          with self.assertRaises(context_manager.AuthorizationException):
   308              self.context_manager.set(
   309                  context_id=ctx_1,
   310                  address_value_list=[{self._create_address('c'): b'5'}])
   311          # 2
   312          with self.assertRaises(context_manager.AuthorizationException):
   313              self.context_manager.get(
   314                  context_id=ctx_1,
   315                  address_list=[self._create_address('a')])
   316  
   317          with self.assertRaises(context_manager.AuthorizationException):
   318              self.context_manager.get(
   319                  context_id=ctx_1,
   320                  address_list=[self._create_address('c')])
   321  
   322      def test_exception_on_invalid_input(self):
   323          """Tests that invalid inputs raise an exception. Tested with invalid
   324          characters, odd number of characters, and too long namespace;
   325  
   326          Notes:
   327              1) Assert that inputs with a namespace with an odd number of
   328                 characters raise a CreateContextException.
   329              2) Assert that inputs with a 71 character namespace raise a
   330                 CreateContextException.
   331              3) Assert that inputs with a namespace with several invalid
   332                 characters raise a CreateContextException.
   333          """
   334  
   335          invalid_input_output1 = '0db7e8zc'  # invalid character
   336          invalid_input_output2 = '7ef84ed' * 10 + '5'  # too long, 71 chars
   337          invalid_input_output3 = 'yy76ftoph7465873ddde389f'  # invalid chars
   338  
   339          valid_input_output1 = 'd8f533bbb74443222daad4'
   340          valid_input_output2 = '77465847465784757848ddddddf'
   341  
   342          state_hash = self.context_manager.get_first_root()
   343  
   344          # 1
   345          with self.assertRaises(context_manager.CreateContextException):
   346              self.context_manager.create_context(
   347                  state_hash=state_hash,
   348                  base_contexts=[],
   349                  inputs=[invalid_input_output1, valid_input_output1],
   350                  outputs=[valid_input_output2])
   351          # 2
   352          with self.assertRaises(context_manager.CreateContextException):
   353              self.context_manager.create_context(
   354                  state_hash=state_hash,
   355                  base_contexts=[],
   356                  inputs=[valid_input_output1, invalid_input_output2],
   357                  outputs=[valid_input_output2])
   358          # 3
   359          with self.assertRaises(context_manager.CreateContextException):
   360              self.context_manager.create_context(
   361                  state_hash=state_hash,
   362                  base_contexts=[],
   363                  inputs=[invalid_input_output3, valid_input_output2],
   364                  outputs=[valid_input_output2, valid_input_output1])
   365  
   366      def test_exception_on_invalid_output(self):
   367          """Tests that invalid outputs raise an exception. Tested with invalid
   368          characters, odd number of characters, and too long namespace;
   369  
   370          Notes:
   371              1) Assert that outputs with a namespace with an odd number of
   372                 characters raise a CreateContextException.
   373              2) Assert that outputs with a 71 character namespace raise a
   374                 CreateContextException.
   375              3) Assert that outputs with a namespace with several invalid
   376                 characters raise a CreateContextException.
   377          """
   378  
   379          invalid_input_output1 = '0db7e87'  # Odd number of characters
   380          invalid_input_output2 = '7ef84ed' * 10 + '5'  # too long, 71 chars
   381          invalid_input_output3 = 'yy76ftoph7465873ddde389f'  # invalid chars
   382  
   383          valid_input_output1 = 'd8f533bbb74443222daad4'
   384          valid_input_output2 = '77465847465784757848ddddddff'
   385  
   386          state_hash = self.context_manager.get_first_root()
   387  
   388          # 1
   389          with self.assertRaises(context_manager.CreateContextException):
   390              self.context_manager.create_context(
   391                  state_hash=state_hash,
   392                  base_contexts=[],
   393                  inputs=[valid_input_output2, valid_input_output1],
   394                  outputs=[invalid_input_output1])
   395          # 2
   396          with self.assertRaises(context_manager.CreateContextException):
   397              self.context_manager.create_context(
   398                  state_hash=state_hash,
   399                  base_contexts=[],
   400                  inputs=[valid_input_output1, valid_input_output2],
   401                  outputs=[invalid_input_output2])
   402          # 3
   403          with self.assertRaises(context_manager.CreateContextException):
   404              self.context_manager.create_context(
   405                  state_hash=state_hash,
   406                  base_contexts=[],
   407                  inputs=[valid_input_output1, valid_input_output2],
   408                  outputs=[valid_input_output2, invalid_input_output3])
   409  
   410      def test_namespace_gets(self):
   411          """Tests that gets for an address under a namespace will return the
   412          correct value.
   413  
   414          Notes:
   415              1) Create ctx_1 and set 'b' to b'8'.
   416              2) squash the previous context creating state_hash_1.
   417              3) Create 2 contexts off of this state hash and assert
   418                 that gets on these contexts retrieve the correct
   419                 value for an address that is not fully specified in the inputs.
   420              4) Set values to addresses in these contexts.
   421              5) Create 1 context off of these prior 2 contexts and assert that
   422                 gets from this context retrieve the correct values for
   423                 addresses that are not fully specified in the inputs. 2 of the
   424                 values are found in the chain of contexts, and 1 is not found
   425                 and so must be retrieved from the merkle tree.
   426          """
   427  
   428          # 1
   429          ctx_1 = self.context_manager.create_context(
   430              state_hash=self.context_manager.get_first_root(),
   431              base_contexts=[],
   432              inputs=[self._create_address('a')],
   433              outputs=[self._create_address('b')])
   434  
   435          self.context_manager.set(
   436              context_id=ctx_1,
   437              address_value_list=[{self._create_address('b'): b'8'}])
   438  
   439          # 2
   440          squash = self.context_manager.get_squash_handler()
   441          state_hash_1 = squash(
   442              state_root=self.context_manager.get_first_root(),
   443              context_ids=[ctx_1],
   444              persist=True,
   445              clean_up=True)
   446  
   447          # 3
   448          ctx_1a = self.context_manager.create_context(
   449              state_hash=state_hash_1,
   450              base_contexts=[],
   451              inputs=[self._create_address('a')[:10]],
   452              outputs=[self._create_address('c')])
   453          self.assertEqual(
   454              self.context_manager.get(
   455                  context_id=ctx_1a,
   456                  address_list=[self._create_address('a')]),
   457              [(self._create_address('a'), None)])
   458  
   459          ctx_1b = self.context_manager.create_context(
   460              state_hash=state_hash_1,
   461              base_contexts=[],
   462              inputs=[self._create_address('b')[:6]],
   463              outputs=[self._create_address('z')])
   464          self.assertEqual(
   465              self.context_manager.get(
   466                  context_id=ctx_1b,
   467                  address_list=[self._create_address('b')]),
   468              [(self._create_address('b'), b'8')])
   469  
   470          # 4
   471          self.context_manager.set(
   472              context_id=ctx_1b,
   473              address_value_list=[{self._create_address('z'): b'2'}])
   474  
   475          self.context_manager.set(
   476              context_id=ctx_1a,
   477              address_value_list=[{self._create_address('c'): b'1'}]
   478          )
   479  
   480          ctx_2 = self.context_manager.create_context(
   481              state_hash=state_hash_1,
   482              base_contexts=[ctx_1a, ctx_1b],
   483              inputs=[
   484                  self._create_address('z')[:10],
   485                  self._create_address('c')[:10],
   486                  self._create_address('b')[:10]
   487              ],
   488              outputs=[self._create_address('w')])
   489  
   490          self.assertEqual(
   491              self.context_manager.get(
   492                  context_id=ctx_2,
   493                  address_list=[self._create_address('z'),
   494                                self._create_address('c'),
   495                                self._create_address('b')]),
   496              [(self._create_address('z'), b'2'),
   497               (self._create_address('c'), b'1'),
   498               (self._create_address('b'), b'8')])
   499  
   500      def test_create_context_with_prior_state(self):
   501          """Tests context creation with prior state from base contexts.
   502  
   503          Notes:
   504              Set up the context:
   505                  Create 3 prior contexts each with 3-5 addresses to set to.
   506                  Make set calls to those addresses.
   507                  Create 1 new context based on those three prior contexts.
   508                  this test method:
   509              Test:
   510                  Make a get call on addresses that are from prior state,
   511                  making assertions about the correct values.
   512          """
   513          context_id = self._setup_context()
   514  
   515          self.assertEqual(self.context_manager.get(
   516              context_id,
   517              [self._create_address(a) for a in
   518               ['llaa', 'yyyy', 'tttt', 'zzoo']]),
   519              [(self._create_address(a), v) for a, v in
   520               [('llaa', b'1'),
   521                ('yyyy', b'11'),
   522                ('tttt', b'12'),
   523                ('zzoo', b'27')]])
   524  
   525      def test_squash(self):
   526          """Tests that squashing a context based on state from other
   527          contexts will result in the same merkle hash as updating the
   528          merkle tree with the same data.
   529  
   530          Notes:
   531              Set up the context
   532  
   533              Test:
   534                  1) Make set calls on several of the addresses.
   535                  2) Squash the context to get a new state hash.
   536                  3) Apply all of the aggregate sets from all
   537                  of the contexts, to another database with a merkle tree.
   538                  4) Assert that the state hashes are the same.
   539          """
   540          # 1)
   541          context_id = self._setup_context()
   542          self.context_manager.set(
   543              context_id,
   544              [{self._create_address(a): v} for a, v in
   545               [('yyyy', b'2'),
   546                ('tttt', b'4')]])
   547  
   548          # 2)
   549          squash = self.context_manager.get_squash_handler()
   550          resulting_state_hash = squash(self.first_state_hash, [context_id],
   551                                        persist=True, clean_up=True)
   552  
   553          # 3)
   554          final_state_to_update = {self._create_address(a): v for a, v in
   555                                   [('llaa', b'1'),
   556                                    ('aall', b'2'),
   557                                    ('nnnn', b'3'),
   558                                    ('zzzz', b'9'),
   559                                    ('yyyy', b'2'),
   560                                    ('tttt', b'4'),
   561                                    ('qqqq', b'13'),
   562                                    ('oooo', b'25'),
   563                                    ('oozz', b'26'),
   564                                    ('zzoo', b'27'),
   565                                    ('ppoo', b'28'),
   566                                    ('aeio', b'29')]}
   567  
   568          test_merkle_tree = MerkleDatabase(self.database_results)
   569          test_resulting_state_hash = test_merkle_tree.update(
   570              final_state_to_update, virtual=False)
   571          # 4)
   572          self.assertEqual(resulting_state_hash, test_resulting_state_hash)
   573  
   574      def test_squash_no_updates(self):
   575          """Tests that squashing a context that has no state updates will return
   576             the starting state root hash.
   577  
   578          Notes:
   579              Set up the context
   580  
   581              Test:
   582                  1) Squash the context.
   583                  2) Assert that the state hash is the same as the starting
   584                  hash.
   585          """
   586          context_id = self.context_manager.create_context(
   587              state_hash=self.first_state_hash,
   588              base_contexts=[],
   589              inputs=[],
   590              outputs=[])
   591          # 1)
   592          squash = self.context_manager.get_squash_handler()
   593          resulting_state_hash = squash(self.first_state_hash, [context_id],
   594                                        persist=True, clean_up=True)
   595          # 2
   596          self.assertIsNotNone(resulting_state_hash)
   597          self.assertEqual(resulting_state_hash, self.first_state_hash)
   598  
   599      def test_squash_deletes_no_update(self):
   600          """Tests that squashing a context that has no state updates,
   601          due to sets that were subsequently deleted, will return
   602          the starting state root hash.
   603  
   604          Notes:
   605              Set up the context
   606  
   607              Test:
   608                  1) Send Updates that reverse each other.
   609                  2) Squash the context.
   610                  3) Assert that the state hash is the same as the starting
   611                  hash.
   612          """
   613          context_id = self.context_manager.create_context(
   614              state_hash=self.first_state_hash,
   615              base_contexts=[],
   616              inputs=[],
   617              outputs=[self._create_address(a) for a in
   618                       ['yyyy', 'tttt']])
   619  
   620          # 1)
   621          self.context_manager.set(
   622              context_id,
   623              [{self._create_address(a): v} for a, v in
   624               [('yyyy', b'2'),
   625                ('tttt', b'4')]])
   626          self.context_manager.delete(
   627              context_id,
   628              [self._create_address(a) for a in
   629               ['yyyy', 'tttt']])
   630  
   631          # 2)
   632          squash = self.context_manager.get_squash_handler()
   633          resulting_state_hash = squash(self.first_state_hash, [context_id],
   634                                        persist=True, clean_up=True)
   635          # 3)
   636          self.assertIsNotNone(resulting_state_hash)
   637          self.assertEqual(resulting_state_hash, self.first_state_hash)
   638  
   639      def test_reads_from_context_w_several_writes(self):
   640          """Tests that those context values that have been written to the
   641          Merkle tree, or that have been set to a base_context, will have the
   642          correct value at the address for a given context.
   643  
   644                                                 ->context_id_a1
   645                                                 |              |
   646                                                 |              |
   647                                                 |              |
   648          sh0-->context_id1-->sh1-->context_a-----              -->context_id_b
   649                                                 |              |
   650                                                 |              |
   651                                                 |              |
   652                                                 |              |
   653                                                 -->context_id_a2
   654  
   655          Notes:
   656  
   657              Test:
   658                  1. From a Merkle Tree with only the root node in it, create a
   659                     context and set several values, and then squash that context
   660                     upon the first state hash.
   661                  2. Create a context with no base context, based on
   662                     the merkle root computed from the first squash.
   663                     Assert that gets from this context will provide
   664                     values that were set in the first context.
   665                  3. Write to all of the available outputs
   666                  4. Create a new context based on context_a, from #2,
   667                  5. Assert that gets from this context equal the values set
   668                     to Context A.
   669                  6. Create a new context based on context_a and set values to
   670                     this context.
   671                  7. Create a new context based on the 2 contexts made in 4 and 6
   672                  8. From this context assert that gets equal the correct values
   673                     set in the prior contexts.
   674          """
   675  
   676          squash = self.context_manager.get_squash_handler()
   677          test_addresses = self._create_txn_inputs_outputs()
   678  
   679          # 1)
   680          context_id1 = self.context_manager.create_context(
   681              state_hash=self.first_state_hash,
   682              inputs=test_addresses.inputs,
   683              outputs=test_addresses.outputs,
   684              base_contexts=[])
   685  
   686          values1 = [bytes(i) for i in range(len(test_addresses.writes))]
   687          self.context_manager.set(
   688              context_id1,
   689              [{a: v} for a, v in zip(test_addresses.writes, values1)])
   690          sh1 = squash(
   691              state_root=self.first_state_hash,
   692              context_ids=[context_id1],
   693              persist=True,
   694              clean_up=True)
   695  
   696          # 2)
   697          context_a = self.context_manager.create_context(
   698              state_hash=sh1,
   699              inputs=test_addresses.writes,  # read from every address written to
   700              outputs=test_addresses.outputs,
   701              base_contexts=[]
   702          )
   703  
   704          address_values = self.context_manager.get(
   705              context_a,
   706              list(test_addresses.writes)
   707          )
   708          self.assertEqual(
   709              address_values,
   710              [(a, v) for a, v in zip(test_addresses.writes, values1)]
   711          )
   712  
   713          # 3)
   714          values2 = [bytes(v.encode()) for v in test_addresses.outputs]
   715          self.context_manager.set(
   716              context_id=context_a,
   717              address_value_list=[{a: v} for
   718                                  a, v in zip(test_addresses.outputs, values2)])
   719  
   720          # 4)
   721          context_id_a1 = self.context_manager.create_context(
   722              state_hash=sh1,
   723              inputs=test_addresses.outputs,
   724              outputs=test_addresses.outputs,
   725              base_contexts=[context_a]
   726          )
   727  
   728          # 5)
   729          c_ida1_address_values = self.context_manager.get(
   730              context_id=context_id_a1,
   731              address_list=list(test_addresses.outputs)
   732          )
   733          self.assertEqual(
   734              c_ida1_address_values,
   735              [(a, v) for a, v in zip(test_addresses.outputs, values2)]
   736          )
   737  
   738          # 6)
   739          test_addresses2 = self._create_txn_inputs_outputs(80)
   740          context_id_a2 = self.context_manager.create_context(
   741              state_hash=sh1,
   742              inputs=test_addresses2.inputs,
   743              outputs=test_addresses2.outputs,
   744              base_contexts=[context_a]
   745          )
   746          values3 = [bytes(v.encode()) for v in test_addresses2.writes]
   747          self.context_manager.set(
   748              context_id=context_id_a2,
   749              address_value_list=[{a: v} for
   750                                  a, v in zip(test_addresses2.writes, values3)],
   751          )
   752  
   753          # 7)
   754          context_id_b = self.context_manager.create_context(
   755              state_hash=sh1,
   756              inputs=test_addresses2.writes + test_addresses.outputs,
   757              outputs=[],
   758              base_contexts=[context_id_a1, context_id_a2]
   759          )
   760  
   761          # 8)
   762          self.assertEqual(
   763              self.context_manager.get(
   764                  context_id_b,
   765                  list(test_addresses2.writes + test_addresses.outputs)
   766              ),
   767              [(a, v) for a, v in zip(
   768                  test_addresses2.writes + test_addresses.outputs,
   769                  values3 + values2)]
   770          )
   771  
   772      def test_state_root_after_parallel_ctx(self):
   773          """Tests that the correct state root is calculated after basing one
   774          context off of multiple contexts.
   775  
   776                                i=abcd
   777                                o=aaaa
   778                             +>context_1+
   779                             |  aaaa=1  |
   780                             |          |
   781                 i=llll      |   i=bacd |      i=bbbb,aaaa
   782                 o=llll      |   o=bbbb |      o=cccc,llll
   783          sh0--->ctx_0-->sh1>|-->context_2-+---->context_n---->sh2
   784                 llll=5      |   bbbb=2 |      cccc=4
   785                             |          |      llll=8
   786                             |   i=abcd |
   787                             |   o=cccc |
   788                             +>context_3+
   789                                 cccc=3
   790  
   791          Notes:
   792              Test:
   793                  1. Create a context, set a value in it and squash it into a new
   794                     state hash.
   795                  2. Create 3 contexts based off of the state root from #1.
   796                  3. Set values at addresses to all three contexts.
   797                  4. Base another context off of the contexts from #2.
   798                  5. Set a value to an address in this context that has already
   799                     been set to in the non-base context.
   800                  6. Squash the contexts producing a state hash and assert
   801                     that it equals a state hash obtained by manually updating
   802                     the merkle tree.
   803          """
   804  
   805          sh0 = self.first_state_hash
   806          # 1)
   807          squash = self.context_manager.get_squash_handler()
   808          ctx_1 = self.context_manager.create_context(
   809              state_hash=sh0,
   810              base_contexts=[],
   811              inputs=[self._create_address('llll')],
   812              outputs=[self._create_address('llll')]
   813          )
   814          self.context_manager.set(
   815              context_id=ctx_1,
   816              address_value_list=[{self._create_address('llll'): b'5'}]
   817          )
   818  
   819          sh1 = squash(
   820              state_root=sh0,
   821              context_ids=[ctx_1],
   822              persist=True,
   823              clean_up=True)
   824  
   825          # 2)
   826          context_1 = self.context_manager.create_context(
   827              state_hash=sh1,
   828              base_contexts=[],
   829              inputs=[self._create_address('abcd')],
   830              outputs=[self._create_address('aaaa')])
   831          context_2 = self.context_manager.create_context(
   832              state_hash=sh1,
   833              base_contexts=[],
   834              inputs=[self._create_address('bacd')],
   835              outputs=[self._create_address('bbbb')])
   836          context_3 = self.context_manager.create_context(
   837              state_hash=sh1,
   838              base_contexts=[],
   839              inputs=[self._create_address('abcd')],
   840              outputs=[
   841                  self._create_address('cccc'),
   842                  self._create_address('dddd')
   843              ])
   844  
   845          # 3)
   846          self.context_manager.set(
   847              context_id=context_1,
   848              address_value_list=[{self._create_address('aaaa'): b'1'}]
   849          )
   850          self.context_manager.set(
   851              context_id=context_2,
   852              address_value_list=[{self._create_address('bbbb'): b'2'}]
   853          )
   854          self.context_manager.set(
   855              context_id=context_3,
   856              address_value_list=[{self._create_address('cccc'): b'3'}]
   857          )
   858  
   859          # 4)
   860          context_n = self.context_manager.create_context(
   861              state_hash=sh1,
   862              base_contexts=[context_1, context_2, context_3],
   863              inputs=[
   864                  self._create_address('bbbb'),
   865                  self._create_address('aaaa')
   866              ],
   867              outputs=[
   868                  self._create_address('cccc'),
   869                  self._create_address('llll')
   870              ])
   871  
   872          # 5)
   873          self.context_manager.set(
   874              context_id=context_n,
   875              address_value_list=[{
   876                  self._create_address('cccc'): b'4',
   877                  self._create_address('llll'): b'8'
   878              }])
   879  
   880          # 6)
   881          cm_state_root = squash(
   882              state_root=sh1,
   883              context_ids=[context_n],
   884              persist=False,
   885              clean_up=True)
   886  
   887          tree = MerkleDatabase(self.database_results)
   888          calc_state_root = tree.update({
   889              self._create_address('aaaa'): b'1',
   890              self._create_address('bbbb'): b'2',
   891              self._create_address('cccc'): b'4',
   892              self._create_address('llll'): b'8'
   893          })
   894          self.assertEqual(calc_state_root, cm_state_root)
   895  
   896      def test_complex_basecontext_squash(self):
   897          """Tests complex context basing and squashing.
   898                                              i=qq,dd dd=0
   899                                              o=dd,pp pp=1
   900                                  i=cc,aa  +->context_3_2a_1+|
   901                                  o=dd,ll  |                 |
   902                 i=aa,ab      +->context_2a|  i=aa    aa=0   |
   903                 o=cc,ab      |   dd=10    |  o=aa,ll ll=1   |
   904          sh0->context_1-->sh1|   ll=11    +->context_3_2a_2+|->sh1
   905                 cc=0         |   i=cc,aa  +->context_3_2b_1+|
   906                 ab=1         |   o=nn,mm  |  i=nn,ba mm=0   |
   907                              +->context_2b|  o=mm,ba ba=1   |
   908                                  nn=0     |                 |
   909                                  mm=1     +->context_3_2b_2+|
   910                                              i=nn,oo ab=0
   911                                              o=ab,oo oo=1
   912  
   913          Notes:
   914              Test:
   915                  1. Create a context off of the first state hash, set
   916                     addresses in it, and squash that context, getting a new
   917                     merkle root.
   918                  2. Create 2 contexts with the context in # 1 as the base, and
   919                     for each of these contexts set addresses to values where the
   920                     outputs for each are disjoint.
   921                  3. For each of these 2 contexts create 2 more contexts each
   922                     having one of the contexts in # 2 as the base context, and
   923                     set addresses to values.
   924                  4. Squash the 4 contexts from #3 and assert the state hash
   925                     is equal to a manually computed state hash.
   926          """
   927  
   928          squash = self.context_manager.get_squash_handler()
   929          # 1)
   930          inputs_1 = [self._create_address('aa'),
   931                      self._create_address('ab')]
   932          outputs_1 = [self._create_address('cc'),
   933                       self._create_address('ab')]
   934          context_1 = self.context_manager.create_context(
   935              state_hash=self.first_state_hash,
   936              base_contexts=[],
   937              inputs=inputs_1,
   938              outputs=outputs_1)
   939          self.context_manager.set(
   940              context_id=context_1,
   941              address_value_list=[{a: v} for a, v in zip(
   942                  outputs_1, [bytes(i) for i in range(len(outputs_1))])])
   943  
   944          sh1 = squash(
   945              state_root=self.first_state_hash,
   946              context_ids=[context_1],
   947              persist=True,
   948              clean_up=True)
   949  
   950          # 2)
   951          inputs_2a = [self._create_address('cc'),
   952                       self._create_address('aa')]
   953          outputs_2a = [self._create_address('dd'),
   954                        self._create_address('ll')]
   955          context_2a = self.context_manager.create_context(
   956              state_hash=self.first_state_hash,
   957              base_contexts=[],
   958              inputs=inputs_2a,
   959              outputs=outputs_2a)
   960  
   961          inputs_2b = [self._create_address('cc'),
   962                       self._create_address('aa')]
   963          outputs_2b = [self._create_address('nn'),
   964                        self._create_address('mm')]
   965          context_2b = self.context_manager.create_context(
   966              state_hash=sh1,
   967              base_contexts=[],
   968              inputs=inputs_2b,
   969              outputs=outputs_2b)
   970  
   971          self.context_manager.set(
   972              context_id=context_2a,
   973              address_value_list=[{a: bytes(v)}
   974                                  for a, v in zip(outputs_2a,
   975                                                  range(10,
   976                                                        10 + len(outputs_2a)))]
   977          )
   978          self.context_manager.set(
   979              context_id=context_2b,
   980              address_value_list=[{a: bytes(v)}
   981                                  for a, v in zip(outputs_2b,
   982                                                  range(len(outputs_2b)))]
   983          )
   984  
   985          # 3)
   986          inputs_3_2a_1 = [
   987              self._create_address('qq'),
   988              self._create_address('dd')
   989          ]
   990          outputs_3_2a_1 = [
   991              self._create_address('dd'),
   992              self._create_address('pp')
   993          ]
   994          context_3_2a_1 = self.context_manager.create_context(
   995              state_hash=sh1,
   996              base_contexts=[context_2a],
   997              inputs=inputs_3_2a_1,
   998              outputs=outputs_3_2a_1)
   999          inputs_3_2a_2 = [self._create_address('aa')]
  1000          outputs_3_2a_2 = [
  1001              self._create_address('aa'),
  1002              self._create_address('ll')
  1003          ]
  1004          context_3_2a_2 = self.context_manager.create_context(
  1005              state_hash=sh1,
  1006              base_contexts=[context_2a],
  1007              inputs=inputs_3_2a_2,
  1008              outputs=outputs_3_2a_2)
  1009  
  1010          inputs_3_2b_1 = [
  1011              self._create_address('nn'),
  1012              self._create_address('ab')
  1013          ]
  1014          outputs_3_2b_1 = [
  1015              self._create_address('mm'),
  1016              self._create_address('ba')
  1017          ]
  1018          context_3_2b_1 = self.context_manager.create_context(
  1019              state_hash=sh1,
  1020              base_contexts=[context_2b],
  1021              inputs=inputs_3_2b_1,
  1022              outputs=outputs_3_2b_1)
  1023  
  1024          inputs_3_2b_2 = [
  1025              self._create_address('nn'),
  1026              self._create_address('oo')
  1027          ]
  1028          outputs_3_2b_2 = [
  1029              self._create_address('ab'),
  1030              self._create_address('oo')
  1031          ]
  1032          context_3_2b_2 = self.context_manager.create_context(
  1033              state_hash=sh1,
  1034              base_contexts=[context_2b],
  1035              inputs=inputs_3_2b_2,
  1036              outputs=outputs_3_2b_2)
  1037  
  1038          self.context_manager.set(
  1039              context_id=context_3_2a_1,
  1040              address_value_list=[{a: bytes(v)}
  1041                                  for a, v in zip(outputs_3_2a_1,
  1042                                                  range(len(outputs_3_2a_1)))])
  1043          self.context_manager.set(
  1044              context_id=context_3_2a_2,
  1045              address_value_list=[{a: bytes(v)}
  1046                                  for a, v in zip(outputs_3_2a_2,
  1047                                                  range(len(outputs_3_2a_2)))])
  1048          self.context_manager.set(
  1049              context_id=context_3_2b_1,
  1050              address_value_list=[{a: bytes(v)}
  1051                                  for a, v in zip(outputs_3_2b_1,
  1052                                                  range(len(outputs_3_2b_1)))])
  1053          self.context_manager.set(
  1054              context_id=context_3_2b_2,
  1055              address_value_list=[{a: bytes(v)}
  1056                                  for a, v in zip(outputs_3_2b_2,
  1057                                                  range(len(outputs_3_2b_2)))])
  1058  
  1059          # 4)
  1060          sh2 = squash(
  1061              state_root=sh1,
  1062              context_ids=[context_3_2a_1, context_3_2a_2,
  1063                           context_3_2b_1, context_3_2b_2],
  1064              persist=False,
  1065              clean_up=True)
  1066  
  1067          tree = MerkleDatabase(self.database_results)
  1068          state_hash_from_1 = tree.update(
  1069              set_items={a: v for a, v in zip(outputs_1,
  1070                                              [bytes(i)
  1071                                               for i in range(len(outputs_1))])},
  1072              virtual=False)
  1073  
  1074          self.assertEqual(state_hash_from_1, sh1,
  1075                           "The manually calculated state hash from the first "
  1076                           "context and the one calculated by squashing that "
  1077                           "state hash should be the same")
  1078          tree.set_merkle_root(state_hash_from_1)
  1079  
  1080          test_sh2 = tree.update(
  1081              set_items={
  1082                  self._create_address('aa'): bytes(0),
  1083                  self._create_address('ab'): bytes(0),
  1084                  self._create_address('ba'): bytes(1),
  1085                  self._create_address('dd'): bytes(0),
  1086                  self._create_address('ll'): bytes(1),
  1087                  self._create_address('mm'): bytes(0),
  1088                  self._create_address('oo'): bytes(1),
  1089                  self._create_address('pp'): bytes(1),
  1090                  self._create_address('nn'): bytes(0),
  1091                  self._create_address('cc'): bytes(0)})
  1092  
  1093          self.assertEqual(sh2, test_sh2, "Manually calculated and context "
  1094                           "manager calculated merkle hashes "
  1095                           "are the same")
  1096  
  1097      def test_wildcarded_inputs_outputs(self):
  1098          """Tests the context manager with wildcarded inputs and outputs.
  1099  
  1100          Notes:
  1101              1. Create a context with a wildcarded input and output and
  1102                 another non-wildcarded input and output.
  1103              2. Get an address under the wildcard and set to both the
  1104                 non-wildcarded address and an address under the
  1105                 wildcard.
  1106              3. Squash the context and compare to a manually generated
  1107                 state hash.
  1108          """
  1109  
  1110          # 1
  1111          namespaces = [
  1112              self._create_address('a')[:8],
  1113              self._create_address('b')
  1114          ]
  1115  
  1116          ctx_1 = self.context_manager.create_context(
  1117              inputs=namespaces,
  1118              outputs=namespaces,
  1119              base_contexts=[],
  1120              state_hash=self.first_state_hash)
  1121  
  1122          # 2
  1123          self.context_manager.get(
  1124              context_id=ctx_1,
  1125              address_list=[self._create_address('a')])
  1126  
  1127          self.context_manager.set(
  1128              context_id=ctx_1,
  1129              address_value_list=[{
  1130                  self._create_address('a'): b'1',
  1131                  self._create_address('b'): b'2'
  1132              }])
  1133  
  1134          # 3
  1135          squash = self.context_manager.get_squash_handler()
  1136  
  1137          tree = MerkleDatabase(self.database_results)
  1138          tree.set_merkle_root(self.first_state_hash)
  1139  
  1140          calculated_state_root = tree.update(
  1141              set_items={self._create_address('a'): b'1',
  1142                         self._create_address('b'): b'2'})
  1143  
  1144          state_root = squash(
  1145              state_root=self.first_state_hash,
  1146              context_ids=[ctx_1],
  1147              persist=True,
  1148              clean_up=True)
  1149  
  1150          self.assertEqual(state_root, calculated_state_root)
  1151  
  1152      @unittest.skip("Necessary to catch scheduler bugs--Depth-first search")
  1153      def test_check_for_bad_combination(self):
  1154          """Tests that the context manager will raise
  1155          an exception if asked to combine contexts, either via base contexts
  1156          in create_context or via squash that shouldn't be
  1157          combined because they share addresses that can't be determined by the
  1158          scheduler to not have been parallel. This is a check on scheduler bugs.
  1159  
  1160          Examples where the context manager should raise an exception on
  1161          duplicate addresses:
  1162          1. Success
  1163                i=a
  1164                o=b
  1165             +>ctx_1+
  1166          dup|->b=3 |
  1167             |      |
  1168          sh0|      ----->state hash or context
  1169             |  i=q |
  1170             |  o=b |
  1171             +>ctx_2+
  1172          dup-->b=2
  1173          2.
  1174                        i=b
  1175                        o=d
  1176                     +>ctx_1a_1+
  1177                     |  d=4    |
  1178               i=a   |         |
  1179               o=b   |         |
  1180             +>ctx_1a|         |
  1181             | b=2   |  i=b    |
  1182             |       |  o=c    |
  1183          sh0|       +>ctx_1a_2|
  1184             |     dup-> c=7   |------>state hash or context
  1185             |  i=a  +>ctx_1b_1|
  1186             |  o=c  |         |
  1187             +>ctx_1b|         |
  1188          dup-->c=5  |  i=t    |
  1189                     |  o=p    |
  1190                     +>ctx_1b_2+
  1191                        p=8
  1192  
  1193          3.
  1194                        i=b
  1195                        o=d
  1196                     +>ctx_1a_1+
  1197                     |  d=4    |   i=d,c
  1198               i=a   |         |   o=n
  1199               o=b   |         <>ctx_3a+
  1200             +>ctx_1a|         |   n=5 |
  1201             | b=2   |  i=b    |       |
  1202             |       |  o=c    |       |
  1203          sh0|       +>ctx_1a_2+       <----->state hash or context
  1204             |   dup--> c=7            |
  1205             |  i=a  +>ctx_1b_1+       |
  1206             |  o=c  |         |  i=c  |
  1207             +>ctx_1b|         |  o=q  |
  1208                c=5  |  i=c    <>ctx_3b+
  1209                     |  o=c    |  q=5
  1210                     +>ctx_1b_2+
  1211                 dup--> c=1
  1212  
  1213          """
  1214  
  1215          # 1.
  1216          squash = self.context_manager.get_squash_handler()
  1217          sh0 = self.first_state_hash
  1218          inputs_1 = [self._create_address('a')]
  1219          outputs_1 = [self._create_address('b')]
  1220          ctx_1 = self.context_manager.create_context(
  1221              state_hash=sh0,
  1222              base_contexts=[],
  1223              inputs=inputs_1,
  1224              outputs=outputs_1
  1225          )
  1226          self.context_manager.set(
  1227              context_id=ctx_1,
  1228              address_value_list=[{self._create_address('b'): b'3'}]
  1229          )
  1230  
  1231          inputs_2 = [self._create_address('q')]
  1232          outputs_2 = [self._create_address('b')]
  1233          ctx_2 = self.context_manager.create_context(
  1234              state_hash=sh0,
  1235              base_contexts=[],
  1236              inputs=inputs_2,
  1237              outputs=outputs_2)
  1238          self.context_manager.set(
  1239              context_id=ctx_2,
  1240              address_value_list=[{
  1241                  self._create_address('b'): b'2'
  1242              }])
  1243  
  1244          try:
  1245              squash(
  1246                  state_root=sh0,
  1247                  context_ids=[ctx_1, ctx_2],
  1248                  persist=True,
  1249                  clean_up=True)
  1250              self.fail("squash of two contexts with a duplicate address")
  1251          except Exception:
  1252              pass
  1253  
  1254      def test_simple_read_write_delete(self):
  1255          """Tests that after sets and deletes, subsequent contexts have the
  1256          correct value in the context for an address.
  1257  
  1258                         i:a
  1259                         o:b
  1260                     +-->ctx_2a+
  1261                     |   s:b:2 |
  1262                     |         |
  1263                i:a  |         |    i:b        i:a,b,c
  1264                o:a  |         |    o:b,c      o:c
  1265          sh0+->ctx_1|         <--->ctx_3+---->ctx_4+------>sh1
  1266                s:a:1|         |    d:b,c      s:c:4
  1267                     |         |
  1268                     |   i:a   |
  1269                     |   o:c   |
  1270                     +-->ctx_2b+
  1271                         s:c:2
  1272  
  1273          Notes:
  1274              1. From the diagram:
  1275                  - ctx_1, with input 'a' and output 'a' will have 'a' set to
  1276                    b'1'.
  1277                  - ctx_2a will have 'b' set to b'2'
  1278                  - ctx_2b will have 'c' set to b'2'
  1279                  - ctx_3 will delete both 'b' and 'c'
  1280                  - ctx_4 will set 'c' to b'4'
  1281                  - ctx_4 will be squashed along with it's base contexts into
  1282                    a new state hash.
  1283              2. Assertions
  1284                  - Assert for every context that it has the correct state
  1285                    before the set or delete.
  1286          """
  1287  
  1288          sh0 = self.context_manager.get_first_root()
  1289  
  1290          ctx_1 = self.context_manager.create_context(
  1291              state_hash=sh0,
  1292              base_contexts=[],
  1293              inputs=[self._create_address('a')],
  1294              outputs=[self._create_address('a')])
  1295  
  1296          self.assertEqual(self.context_manager.get(
  1297              ctx_1, [self._create_address('a')]),
  1298              [(self._create_address('a'), None)],
  1299              "ctx_1 has no value for 'a'")
  1300  
  1301          self.context_manager.set(ctx_1, [{self._create_address('a'): b'1'}])
  1302  
  1303          ctx_2a = self.context_manager.create_context(
  1304              state_hash=sh0,
  1305              base_contexts=[ctx_1],
  1306              inputs=[self._create_address('a')],
  1307              outputs=[self._create_address('b')])
  1308  
  1309          self.assertEqual(self.context_manager.get(
  1310              ctx_2a, [self._create_address('a')]),
  1311              [(self._create_address('a'), b'1')],
  1312              "ctx_2a has the value b'1' for 'a'")
  1313  
  1314          self.context_manager.set(ctx_2a, [{self._create_address('b'): b'2'}])
  1315  
  1316          ctx_2b = self.context_manager.create_context(
  1317              state_hash=sh0,
  1318              base_contexts=[ctx_1],
  1319              inputs=[self._create_address('a')],
  1320              outputs=[self._create_address('c')])
  1321  
  1322          self.assertEqual(self.context_manager.get(
  1323              ctx_2b, [self._create_address('a')]),
  1324              [(self._create_address('a'), b'1')],
  1325              "ctx_2b has the value b'1' for 'a'")
  1326  
  1327          self.context_manager.set(ctx_2b, [{self._create_address('c'): b'2'}])
  1328  
  1329          ctx_3 = self.context_manager.create_context(
  1330              state_hash=sh0,
  1331              base_contexts=[ctx_2b, ctx_2a],
  1332              inputs=[self._create_address('b')],
  1333              outputs=[self._create_address('b'), self._create_address('c')])
  1334  
  1335          self.assertEqual(self.context_manager.get(
  1336              ctx_3, [self._create_address('b')]),
  1337              [(self._create_address('b'), b'2')],
  1338              "ctx_3 has the value b'2' for 'b'")
  1339  
  1340          self.context_manager.delete(ctx_3, [self._create_address('b'),
  1341                                              self._create_address('c')])
  1342  
  1343          ctx_4 = self.context_manager.create_context(
  1344              state_hash=sh0,
  1345              base_contexts=[ctx_3],
  1346              inputs=[
  1347                  self._create_address('a'),
  1348                  self._create_address('b'),
  1349                  self._create_address('c')
  1350              ],
  1351              outputs=[self._create_address('c')])
  1352  
  1353          self.assertEqual(self.context_manager.get(
  1354              ctx_4, [self._create_address('a'),
  1355                      self._create_address('b'),
  1356                      self._create_address('c')]),
  1357              [(self._create_address('a'), b'1'),
  1358               (self._create_address('b'), None),
  1359               (self._create_address('c'), None)],
  1360              "ctx_4 has the correct values in state for 'a','b', 'c'")
  1361  
  1362          self.context_manager.set(ctx_4, [{self._create_address('c'): b'4'}])
  1363  
  1364          squash = self.context_manager.get_squash_handler()
  1365  
  1366          sh1 = squash(
  1367              state_root=sh0,
  1368              context_ids=[ctx_4],
  1369              persist=True,
  1370              clean_up=True)
  1371  
  1372          tree = MerkleDatabase(self.database_results)
  1373  
  1374          sh1_assertion = tree.update({
  1375              self._create_address('a'): b'1',
  1376              self._create_address('c'): b'4'
  1377          })
  1378  
  1379          self.assertEqual(sh1, sh1_assertion,
  1380                           "The context manager must "
  1381                           "calculate the correct state hash")
  1382  
  1383      def test_complex_read_write_delete(self):
  1384          """Tests complex reads, writes, and deletes from contexts.
  1385  
  1386                    i:a
  1387                    o:b                           i:a
  1388                 +->ctx_1a+                       o:d
  1389                 |  s:b   |                    +->ctx_3a+
  1390                 |        |                    |  d:d   |
  1391                 |  i:a   |             i:a    |        |    i:""
  1392                 |  o:c   |             o:""   |        |    o:""
  1393          sh0+----->ctx_1b<--->sh1+---->ctx_2+-+        <--->ctx_4+->sh2
  1394                 |  s:c   |             d:c    |  i:c   |
  1395                 |  i:a   |             s:e    |  o:b   |
  1396                 |  o:d   |                    +->ctx_3b+
  1397                 +->ctx_1c+                       d:b
  1398                    s:d
  1399  
  1400          Notes:
  1401              1. Aside from the initial state hash, there are two squashed
  1402                 state hashes. There are sets in ctx_1* and then after a squash,
  1403                 deletes of the same addresses.
  1404              2. Assertions are made for ctx_3b that 'c' is not in state, for
  1405                 ctx_4 that 'b', 'c', and 'd' are not in state.
  1406          """
  1407  
  1408          sh0 = self.first_state_hash
  1409          squash = self.context_manager.get_squash_handler()
  1410  
  1411          ctx_1a = self.context_manager.create_context(
  1412              state_hash=sh0,
  1413              base_contexts=[],
  1414              inputs=[self._create_address('a')],
  1415              outputs=[self._create_address('b')])
  1416  
  1417          ctx_1b = self.context_manager.create_context(
  1418              state_hash=sh0,
  1419              base_contexts=[],
  1420              inputs=[self._create_address('a')],
  1421              outputs=[self._create_address('c')])
  1422  
  1423          ctx_1c = self.context_manager.create_context(
  1424              state_hash=sh0,
  1425              base_contexts=[],
  1426              inputs=[self._create_address('a')],
  1427              outputs=[self._create_address('d')])
  1428  
  1429          self.context_manager.set(ctx_1a, [{self._create_address('b'): b'1'}])
  1430  
  1431          self.context_manager.set(ctx_1b, [{self._create_address('c'): b'2'}])
  1432  
  1433          self.context_manager.set(ctx_1c, [{self._create_address('d'): b'3'}])
  1434  
  1435          sh1 = squash(
  1436              state_root=sh0,
  1437              context_ids=[ctx_1c, ctx_1b, ctx_1a],
  1438              persist=True,
  1439              clean_up=True)
  1440  
  1441          ctx_2 = self.context_manager.create_context(
  1442              state_hash=sh1,
  1443              base_contexts=[],
  1444              inputs=[self._create_address('a')],
  1445              outputs=[""])
  1446  
  1447          self.context_manager.delete(ctx_2, [self._create_address('c')])
  1448  
  1449          self.context_manager.set(ctx_2, [{self._create_address('e'): b'2'}])
  1450  
  1451          ctx_3a = self.context_manager.create_context(
  1452              state_hash=sh1,
  1453              base_contexts=[ctx_2],
  1454              inputs=[self._create_address('a')],
  1455              outputs=[self._create_address('d')])
  1456  
  1457          self.context_manager.delete(ctx_3a, [self._create_address('d')])
  1458  
  1459          ctx_3b = self.context_manager.create_context(
  1460              state_hash=sh1,
  1461              base_contexts=[ctx_2],
  1462              inputs=[self._create_address('c')],
  1463              outputs=[self._create_address('b')])
  1464  
  1465          self.assertEqual(
  1466              self.context_manager.get(ctx_3b, [self._create_address('c')]),
  1467              [(self._create_address('c'), None)],
  1468              "Address 'c' has already been deleted from state.")
  1469  
  1470          self.context_manager.delete(ctx_3b, [self._create_address('b')])
  1471  
  1472          ctx_4 = self.context_manager.create_context(
  1473              state_hash=sh1,
  1474              base_contexts=[ctx_3b, ctx_3a],
  1475              inputs=[""],
  1476              outputs=[""])
  1477  
  1478          self.assertEqual(
  1479              self.context_manager.get(ctx_4, [self._create_address('b'),
  1480                                               self._create_address('c'),
  1481                                               self._create_address('d')]),
  1482              [(self._create_address('b'), None),
  1483               (self._create_address('c'), None),
  1484               (self._create_address('d'), None)],
  1485              "Addresses 'b', 'c', and 'd' have been deleted from state.")
  1486  
  1487          sh2 = squash(
  1488              state_root=sh1,
  1489              context_ids=[ctx_4],
  1490              persist=True,
  1491              clean_up=True)
  1492  
  1493          tree = MerkleDatabase(self.database_results)
  1494  
  1495          sh1_assertion = tree.update(
  1496              {
  1497                  self._create_address('b'): b'1',
  1498                  self._create_address('c'): b'2',
  1499                  self._create_address('d'): b'3'
  1500              },
  1501              virtual=False)
  1502  
  1503          self.assertEqual(sh1, sh1_assertion,
  1504                           "The middle state hash must be correct.")
  1505  
  1506          tree.set_merkle_root(sh1)
  1507  
  1508          sh2_assertion = tree.update(
  1509              {
  1510                  self._create_address('e'): b'2'
  1511              },
  1512              delete_items=[
  1513                  self._create_address('b'),
  1514                  self._create_address('c'),
  1515                  self._create_address('d')
  1516              ],
  1517              virtual=False)
  1518          self.assertEqual(sh2, sh2_assertion,
  1519                           "The final state hash must be correct")