Ejemplo n.º 1
0
 def setUp(self):
     self.context_manager = ContextManager(dict_database.DictDatabase())
     squash_handler = self.context_manager.get_squash_handler()
     self.first_state_root = self.context_manager.get_first_root()
     self.scheduler = ParallelScheduler(squash_handler,
                                        self.first_state_root,
                                        always_persist=False)
Ejemplo n.º 2
0
    def setUp(self):
        self.context_manager = ContextManager(dict_database.DictDatabase())
        squash_handler = self.context_manager.get_squash_handler()
        self.first_state_root = self.context_manager.get_first_root()
        self.scheduler = ParallelScheduler(squash_handler,
                                           self.first_state_root,
                                           always_persist=False)

        self._context = create_context('secp256k1')
        self._crypto_factory = CryptoFactory(self._context)
Ejemplo n.º 3
0
    def create_scheduler(self,
                         first_state_root,
                         always_persist=False):

        # Useful for a logical first state root of ""
        if not first_state_root:
            first_state_root = self._context_manager.get_first_root()

        if self._scheduler_type == "serial":
            scheduler = SerialScheduler(
                squash_handler=self._context_manager.get_squash_handler(),
                first_state_hash=first_state_root,
                always_persist=always_persist)
        elif self._scheduler_type == "parallel":
            scheduler = ParallelScheduler(
                squash_handler=self._context_manager.get_squash_handler(),
                first_state_hash=first_state_root,
                always_persist=always_persist)

        else:
            raise AssertionError(
                "Scheduler type must be either serial or parallel. Current"
                " scheduler type is {}.".format(self._scheduler_type))

        self.execute(scheduler=scheduler)
        return scheduler
Ejemplo n.º 4
0
 def _setup_parallel_scheduler(self):
     context_manager = self._context_manager
     squash_handler = context_manager.get_squash_handler()
     first_state_root = context_manager.get_first_root()
     scheduler = ParallelScheduler(squash_handler,
                                   first_state_root,
                                   always_persist=False)
     return context_manager, scheduler
Ejemplo n.º 5
0
    def create_scheduler(self, first_state_root, always_persist=False):
        if self._scheduler_type == "serial":
            return SerialScheduler(
                squash_handler=self._context_manager.get_squash_handler(),
                first_state_hash=first_state_root,
                always_persist=always_persist)
        elif self._scheduler_type == "parallel":
            return ParallelScheduler(
                squash_handler=self._context_manager.get_squash_handler(),
                first_state_hash=first_state_root,
                always_persist=always_persist)

        else:
            raise AssertionError(
                "Scheduler type must be either serial or parallel. Current"
                " scheduler type is {}.".format(self._scheduler_type))
Ejemplo n.º 6
0
    def create_scheduler(self,
                         squash_handler,
                         first_state_root,
                         context_handlers=None,
                         always_persist=False):
        LOGGER.debug("create scheduler_type=%s", self._scheduler_type)
        if self._scheduler_type == "serial":
            return SerialScheduler(squash_handler=squash_handler,
                                   first_state_hash=first_state_root,
                                   always_persist=always_persist,
                                   context_handlers=context_handlers)
        elif self._scheduler_type == "parallel":
            return ParallelScheduler(squash_handler=squash_handler,
                                     first_state_hash=first_state_root,
                                     always_persist=always_persist,
                                     context_handlers=context_handlers)

        else:
            raise AssertionError(
                "Scheduler type must be either serial or parallel. Current"
                " scheduler type is {}.".format(self._scheduler_type))
Ejemplo n.º 7
0
class TestParallelScheduler(unittest.TestCase):
    def setUp(self):
        self.context_manager = ContextManager(dict_database.DictDatabase(),
                                              state_delta_store=Mock())
        squash_handler = self.context_manager.get_squash_handler()
        self.first_state_root = self.context_manager.get_first_root()
        self.scheduler = ParallelScheduler(squash_handler,
                                           self.first_state_root,
                                           always_persist=False)

    def tearDown(self):
        self.context_manager.stop()

    def test_add_to_finalized_scheduler(self):
        """Tests that a finalized scheduler raise exception on add_batch().

        This test creates a scheduler, finalizes it, and calls add_batch().
        The result is expected to be a SchedulerError, since adding a batch
        to a finalized scheduler is invalid.
        """
        private_key = signing.generate_privkey()
        public_key = signing.generate_pubkey(private_key)

        # Finalize prior to attempting to add a batch.
        self.scheduler.finalize()

        txn, _ = create_transaction(payload='a'.encode(),
                                    private_key=private_key,
                                    public_key=public_key)

        batch = create_batch(transactions=[txn],
                             private_key=private_key,
                             public_key=public_key)

        # scheduler.add_batch(batch) should throw a SchedulerError due to
        # the finalized status of the scheduler.
        self.assertRaises(SchedulerError,
                          lambda: self.scheduler.add_batch(batch))

    def test_set_result_on_unscheduled_txn(self):
        """Tests that a scheduler will reject a result on an unscheduled
        transaction.

        Creates a batch with a single transaction, adds the batch to the
        scheduler, then immediately attempts to set the result for the
        transaction without first causing it to be scheduled (by using an
        iterator or calling next_transaction()).
        """
        private_key = signing.generate_privkey()
        public_key = signing.generate_pubkey(private_key)

        txn, _ = create_transaction(payload='a'.encode(),
                                    private_key=private_key,
                                    public_key=public_key)

        batch = create_batch(transactions=[txn],
                             private_key=private_key,
                             public_key=public_key)

        self.scheduler.add_batch(batch)

        self.assertRaises(
            SchedulerError,
            lambda: self.scheduler.set_transaction_execution_result(
                txn.header_signature, False, None))

    def test_transaction_order(self):
        """Tests the that transactions are returned in order added.

        Adds three batches with varying number of transactions, then tests
        that they are returned in the appropriate order when using an iterator.

        This test also creates a second iterator and verifies that both
        iterators return the same transactions.

        This test also finalizes the scheduler and verifies that StopIteration
        is thrown by the iterator.
        """
        private_key = signing.generate_privkey()
        public_key = signing.generate_pubkey(private_key)

        txns = []

        for names in [['a', 'b', 'c'], ['d', 'e'], ['f', 'g', 'h', 'i']]:
            batch_txns = []
            for name in names:
                txn, _ = create_transaction(payload=name.encode(),
                                            private_key=private_key,
                                            public_key=public_key)

                batch_txns.append(txn)
                txns.append(txn)

            batch = create_batch(transactions=batch_txns,
                                 private_key=private_key,
                                 public_key=public_key)

            self.scheduler.add_batch(batch)

        iterable1 = iter(self.scheduler)
        iterable2 = iter(self.scheduler)
        for txn in txns:
            scheduled_txn_info = next(iterable1)
            self.assertEqual(scheduled_txn_info, next(iterable2))
            self.assertIsNotNone(scheduled_txn_info)
            self.assertEqual(txn.payload, scheduled_txn_info.txn.payload)
            self.scheduler.set_transaction_execution_result(
                txn.header_signature, False, None)

        self.scheduler.finalize()
        self.assertTrue(self.scheduler.complete(block=False))
        with self.assertRaises(StopIteration):
            next(iterable1)

    def test_transaction_order_with_dependencies(self):
        """Tests the that transactions are returned in the expected order given
        dependencies implied by state.

        Creates one batch with four transactions.
        """
        private_key = signing.generate_privkey()
        public_key = signing.generate_pubkey(private_key)

        txns = []
        headers = []

        txn, header = create_transaction(payload='a'.encode(),
                                         private_key=private_key,
                                         public_key=public_key)
        txns.append(txn)
        headers.append(header)

        txn, header = create_transaction(payload='b'.encode(),
                                         private_key=private_key,
                                         public_key=public_key)
        txns.append(txn)
        headers.append(header)

        txn, header = create_transaction(
            payload='aa'.encode(),
            private_key=private_key,
            public_key=public_key,
            inputs=['000000' + hashlib.sha512('a'.encode()).hexdigest()[:64]],
            outputs=['000000' + hashlib.sha512('a'.encode()).hexdigest()[:64]])
        txns.append(txn)
        headers.append(header)

        txn, header = create_transaction(
            payload='bb'.encode(),
            private_key=private_key,
            public_key=public_key,
            inputs=['000000' + hashlib.sha512('b'.encode()).hexdigest()[:64]],
            outputs=['000000' + hashlib.sha512('b'.encode()).hexdigest()[:64]])
        txns.append(txn)
        headers.append(header)

        batch = create_batch(transactions=txns,
                             private_key=private_key,
                             public_key=public_key)

        self.scheduler.add_batch(batch)
        self.scheduler.finalize()
        self.assertFalse(self.scheduler.complete(block=False))

        iterable = iter(self.scheduler)
        scheduled_txn_info = []

        self.assertEqual(2, self.scheduler.available())
        scheduled_txn_info.append(next(iterable))
        self.assertIsNotNone(scheduled_txn_info[0])
        self.assertEqual(txns[0].payload, scheduled_txn_info[0].txn.payload)
        self.assertFalse(self.scheduler.complete(block=False))

        self.assertEqual(1, self.scheduler.available())
        scheduled_txn_info.append(next(iterable))
        self.assertIsNotNone(scheduled_txn_info[1])
        self.assertEqual(txns[1].payload, scheduled_txn_info[1].txn.payload)
        self.assertFalse(self.scheduler.complete(block=False))

        self.assertEqual(0, self.scheduler.available())
        context_id1 = self.context_manager.create_context(
            state_hash=self.first_state_root,
            inputs=list(headers[1].inputs),
            outputs=list(headers[1].outputs),
            base_contexts=[])
        self.scheduler.set_transaction_execution_result(
            txns[1].header_signature, True, context_id1)

        self.assertEqual(1, self.scheduler.available())
        scheduled_txn_info.append(next(iterable))
        self.assertIsNotNone(scheduled_txn_info[2])
        self.assertEqual(txns[3].payload, scheduled_txn_info[2].txn.payload)
        self.assertFalse(self.scheduler.complete(block=False))

        self.assertEqual(0, self.scheduler.available())
        context_id2 = self.context_manager.create_context(
            state_hash=self.first_state_root,
            inputs=list(headers[0].inputs),
            outputs=list(headers[0].outputs),
            base_contexts=[context_id1])
        self.scheduler.set_transaction_execution_result(
            txns[0].header_signature, True, context_id2)

        self.assertEqual(1, self.scheduler.available())
        scheduled_txn_info.append(next(iterable))
        self.assertIsNotNone(scheduled_txn_info[3])
        self.assertEqual(txns[2].payload, scheduled_txn_info[3].txn.payload)
        self.assertFalse(self.scheduler.complete(block=False))

        self.assertEqual(0, self.scheduler.available())
        context_id3 = self.context_manager.create_context(
            state_hash=self.first_state_root,
            inputs=list(headers[2].inputs),
            outputs=list(headers[2].outputs),
            base_contexts=[context_id2])
        self.scheduler.set_transaction_execution_result(
            txns[2].header_signature, True, context_id3)
        context_id4 = self.context_manager.create_context(
            state_hash=self.first_state_root,
            inputs=list(headers[3].inputs),
            outputs=list(headers[3].outputs),
            base_contexts=[context_id3])
        self.scheduler.set_transaction_execution_result(
            txns[3].header_signature, True, context_id4)

        self.assertEqual(0, self.scheduler.available())
        self.assertTrue(self.scheduler.complete(block=False))
        with self.assertRaises(StopIteration):
            next(iterable)

        result = self.scheduler.get_batch_execution_result(
            batch.header_signature)
        self.assertIsNotNone(result)
        self.assertTrue(result.is_valid)