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")