Exemple #1
0
    def on_check_publish_block(self, force=False):
        """Ask the consensus module if it is time to claim the candidate block
        if it is then, claim it and tell the world about it.
        :return:
            None
        """
        try:
            with self._lock:
                if self._chain_head is not None and\
                        self._candidate_block is None and\
                        self._pending_batches:
                    self._build_candidate_block(self._chain_head)

                if self._candidate_block and (
                            force or
                            self._candidate_block.has_pending_batches()) and \
                        self._candidate_block.check_publish_block():

                    pending_batches = []  # will receive the list of batches
                    # that were not added to the block
                    last_batch = self._candidate_block.last_batch
                    block = self._candidate_block.finalize_block(
                        self._identity_signing_key, pending_batches)
                    self._candidate_block = None
                    # Update the _pending_batches to reflect what we learned.

                    last_batch_index = self._pending_batches.index(last_batch)
                    unsent_batches =\
                        self._pending_batches[last_batch_index + 1:]
                    self._pending_batches =\
                        pending_batches + unsent_batches

                    self._set_gauge(len(self._pending_batches))

                    if block:
                        blkw = BlockWrapper(block)
                        LOGGER.info("Claimed Block: %s", blkw)
                        self._block_sender.send(blkw.block)

                        # We built our candidate, disable processing until
                        # the chain head is updated. Only set this if
                        # we succeeded. Otherwise try again, this
                        # can happen in cases where txn dependencies
                        # did not validate when building the block.
                        self.on_chain_updated(None)

        # pylint: disable=broad-except
        except Exception as exc:
            LOGGER.critical("on_check_publish_block exception.")
            LOGGER.exception(exc)
def create_block(block_num=85,
                 previous_block_id="0000000000000000",
                 block_id="abcdef1234567890",
                 batches=None):
    if batches is None:
        batches = []
    block_header = block_pb2.BlockHeader(block_num=block_num,
                                         state_root_hash="0987654321fedcba",
                                         previous_block_id=previous_block_id)
    block = BlockWrapper(
        block_pb2.Block(header_signature=block_id,
                        header=block_header.SerializeToString(),
                        batches=batches))
    return block
Exemple #3
0
def create_block(batch, block_num, previous_block_id, state_root_hash, signer):
    header = BlockHeader(
        block_num=block_num,
        previous_block_id=previous_block_id,
        state_root_hash=state_root_hash,
        signer_public_key=signer.get_public_key().as_hex(),
    ).SerializeToString()

    block = Block(header=header,
                  batches=[batch],
                  header_signature=signer.sign(header))

    block_wrapper = BlockWrapper(block)
    return block_wrapper
Exemple #4
0
    def test_publish_block(self):
        """
        Test that the Journal will produce blocks and consume those blocks
        to extend the chain.
        :return:
        """
        # construction and wire the journal to the
        # gossip layer.

        btm = BlockTreeManager()
        journal = None
        try:
            journal = Journal(
                block_store=btm.block_store,
                block_cache=btm.block_cache,
                state_view_factory=StateViewFactory(DictDatabase()),
                block_sender=self.block_sender,
                batch_sender=self.batch_sender,
                transaction_executor=self.txn_executor,
                squash_handler=None,
                identity_signing_key=btm.identity_signing_key,
                chain_id_manager=None,
                state_delta_processor=self.state_delta_processor,
                data_dir=None,
                config_dir=None
            )

            self.gossip.on_batch_received = journal.on_batch_received
            self.gossip.on_block_received = journal.on_block_received

            journal.start()

            # feed it a batch
            batch = Batch()
            journal.on_batch_received(batch)

            wait_until(lambda: self.block_sender.new_block is not None, 2)
            self.assertTrue(self.block_sender.new_block is not None)

            block = BlockWrapper(self.block_sender.new_block)
            journal.on_block_received(block)

            # wait for the chain_head to be updated.
            wait_until(lambda: btm.chain_head.identifier ==
                       block.identifier, 2)
            self.assertTrue(btm.chain_head.identifier == block.identifier)
        finally:
            if journal is not None:
                journal.stop()
    def _generate_block(self, payload, previous_block_id, block_num):
        header = BlockHeader(previous_block_id=previous_block_id,
                             signer_pubkey=self.public_key,
                             block_num=block_num)

        block_builder = BlockBuilder(header)
        block_builder.add_batches([self._generate_batch_from_payload(payload)])

        header_bytes = block_builder.block_header.SerializeToString()
        signature = signing.sign(header_bytes, self.identity_signing_key)
        block_builder.set_signature(signature)

        block_wrapper = BlockWrapper(block_builder.build_block())
        LOGGER.debug("Generated %s", dumps_block(block_wrapper))
        return block_wrapper
Exemple #6
0
    def test_block_cache(self):
        block_store = {}
        cache = BlockCache(block_store=block_store,
                           keep_time=1,
                           purge_frequency=1)

        header1 = BlockHeader(previous_block_id="000")
        block1 = BlockWrapper(
            Block(header=header1.SerializeToString(), header_signature="ABC"))

        header2 = BlockHeader(previous_block_id="ABC")
        block2 = BlockWrapper(
            Block(header=header2.SerializeToString(), header_signature="DEF"))

        header3 = BlockHeader(previous_block_id="BCA")
        block3 = BlockWrapper(
            Block(header=header3.SerializeToString(), header_signature="FED"))

        cache[block1.header_signature] = block1
        cache[block2.header_signature] = block2

        # Check that blocks are in the BlockCache
        self.assertIn("ABC", cache)
        self.assertIn("DEF", cache)

        # Wait for purge time to expire
        time.sleep(1)
        # Add "FED"
        cache[block3.header_signature] = block3

        # Check that "ABC" is still in the cache even though the keep time has
        # expired because it has a referecne count of 1 but "DEF" has been
        # removed
        self.assertIn("ABC", cache)
        self.assertNotIn("DEF", cache)
        self.assertIn("FED", cache)
Exemple #7
0
    def deserialize_block(value):
        """
        Deserialize a byte string into a BlockWrapper

        Args:
            value (bytes): the byte string to deserialze

        Returns:
            BlockWrapper: a block wrapper instance
        """
        # Block id strings are stored under batch/txn ids for reference.
        # Only Blocks, not ids or Nones, should be returned by _get_block.
        block = Block()
        block.ParseFromString(value)
        return BlockWrapper(status=BlockStatus.Valid, block=block)
    def generate_block(self,
                       previous_block=None,
                       add_to_store=False,
                       add_to_cache=False,
                       batch_count=0,
                       status=BlockStatus.Unknown,
                       invalid_consensus=False,
                       invalid_batch=False,
                       invalid_signature=False,
                       weight=0):

        previous = self._get_block(previous_block)
        if previous is None:
            previous = self.chain_head

        self.block_publisher.on_chain_updated(previous)

        while self.block_sender.new_block is None:
            self.block_publisher.on_batch_received(
                self._generate_batch_from_payload(''))
            self.block_publisher.on_check_publish_block(True)

        block_from_sender = self.block_sender.new_block
        self.block_sender.new_block = None

        block_wrapper = BlockWrapper(block_from_sender)

        if invalid_signature:
            block_wrapper.block.header_signature = "BAD"

        if invalid_consensus:
            block_wrapper.header.consensus = b'BAD'

        if invalid_batch:
            block_wrapper.block.batches.extend(
                [self._generate_batch_from_payload('BAD')])

        block_wrapper.weight = weight
        block_wrapper.status = status

        if add_to_cache:
            self.block_cache[block_wrapper.identifier] = block_wrapper

        if add_to_store:
            self.block_store[block_wrapper.identifier] = block_wrapper

        LOGGER.debug("Generated %s", dumps_block(block_wrapper))
        return block_wrapper
Exemple #9
0
    def _make_block(self, txns_family, signer_pubkey, same_pubkey=True):
        transactions = []
        for family in txns_family:
            txn_header = TransactionHeader(
                family_name=family,
                signer_pubkey=signer_pubkey)
            txn = Transaction(header=txn_header.SerializeToString())
            transactions.append(txn)

        batch = Batch(transactions=transactions)
        if same_pubkey:
            block_header = BlockHeader(signer_pubkey=signer_pubkey)
        else:
            block_header = BlockHeader(signer_pubkey="other")
        block = Block(header=block_header.SerializeToString(), batches=[batch])
        return BlockWrapper(block)
Exemple #10
0
    def test_reject_non_genesis_block(self):
        """This test should show that a block with any previous blocks should
        fail verification.
        """
        block_cache = Mock()
        state_view_factory = Mock()
        data_dir = 'mock_dir'
        block_verifier = BlockVerifier(block_cache, state_view_factory,
                                       data_dir)

        block = Block(header=BlockHeader(
            previous_block_id='some_prev_block_id').SerializeToString())
        block_wrapper = BlockWrapper(block)

        result = block_verifier.verify_block(block_wrapper)
        self.assertFalse(result)
Exemple #11
0
    def test_verify_genesis_block(self):
        """This test should verify that a block with the NULL_BLOCK_IDENTIFIER
        should be considered a valid block using this consensus module.
        """
        block_cache = Mock()
        state_view_factory = Mock()
        data_dir = 'mock_dir'
        block_verifier = BlockVerifier(block_cache, state_view_factory,
                                       data_dir)

        block = Block(header=BlockHeader(
            previous_block_id=NULL_BLOCK_IDENTIFIER).SerializeToString())
        block_wrapper = BlockWrapper(block)

        result = block_verifier.verify_block(block_wrapper)
        self.assertTrue(result)
Exemple #12
0
    def _create_chain(self, length):
        chain = []
        previous_block_id = NULL_BLOCK_IDENTIFIER
        for i in range(length):
            block = BlockWrapper(
                Block(header_signature='abcd{}'.format(i),
                      header=BlockHeader(block_num=i,
                                         previous_block_id=previous_block_id).
                      SerializeToString()))

            previous_block_id = block.identifier

            chain.append(block)

        chain.reverse()

        return chain
Exemple #13
0
    def test_duplicate_transactions(self):
        '''
        Test discards batches that have duplicate transactions in them.
        '''
        # receive batches, then try again (succeeding)
        self.batches = self.batches[1:2]
        self.receive_batches()
        self.publish_block()
        self.assert_block_published()
        self.update_chain_head(BlockWrapper(self.result_block))
        self.verify_block()

        # build a new set of batches with the same transactions in them
        self.batches = self.make_batches_with_duplicate_txn()
        self.receive_batches()
        self.publish_block()
        self.assert_no_block_published() # block should be empty after batch
Exemple #14
0
    def generate_block(self,
                       previous_block=None,
                       add_to_store=False,
                       add_to_cache=False,
                       batch_count=0,
                       status=BlockStatus.Unknown,
                       invalid_consensus=False,
                       invalid_batch=False,
                       invalid_signature=False,
                       weight=None):

        previous = self._get_block(previous_block)
        if previous is None:
            previous = self.chain_head

        self.block_publisher.on_chain_updated(previous)

        while self.block_sender.new_block is None:
            self.block_publisher.on_batch_received(Batch())
            self.block_publisher.on_check_publish_block(True)

        block = self.block_sender.new_block
        self.block_sender.new_block = None

        block = BlockWrapper(block)

        if invalid_signature:
            block.block.header_signature = "BAD"

        block.weight = weight
        block.status = status

        if add_to_cache:
            self.block_cache[block.identifier] = block

        if add_to_store:
            if block.weight is None:
                state_view = self.state_view_factory.create_view(None)
                tmv = mock_consensus.\
                    BlockVerifier(block_cache=self.block_cache,
                                  state_view=state_view)
                block.weight = tmv.compute_block_weight(block)
            self.block_store[block.identifier] = block

        return block
Exemple #15
0
    def _build_block(self, chain_head):
        """ Build a candidate block
        """
        block_header = BlockHeader(
            block_num=chain_head.block_num + 1,
            previous_block_id=chain_head.header_signature)
        self._consensus.initialize_block(block_header)

        # create a new scheduler
        # TBD move factory in to executor for easier mocking --
        # Yes I want to make fun of it.
        self._scheduler = self._transaction_executor.create_scheduler(
            self._squash_handler, chain_head.state_root_hash)

        self._transaction_executor.execute(self._scheduler)
        for batch in self._pending_batches:
            self._scheduler.add_batch(batch)
        self._pending_batches = []
        block = BlockWrapper(block_header)
        return block
Exemple #16
0
    def create_block(self, payload='payload', batch_count=1,
                     previous_block_id=NULL_BLOCK_IDENTIFIER, block_num=0):
        header = BlockHeader(
            previous_block_id=previous_block_id,
            signer_pubkey=self.public_key,
            block_num=block_num)

        block_builder = BlockBuilder(header)
        block_builder.add_batches(
            [self._generate_batch_from_payload(payload)
                for _ in range(batch_count)])
        block_builder.set_state_hash('0'*70)

        header_bytes = block_builder.block_header.SerializeToString()
        signature = signing.sign(header_bytes, self.identity_signing_key)
        block_builder.set_signature(signature)

        block_wrapper = BlockWrapper(block_builder.build_block())
        LOGGER.debug("Generated %s", dumps_block(block_wrapper))
        return block_wrapper
Exemple #17
0
    def test_publish_block(self):
        """
        Test that the Journal will produce blocks and consume those blocks
        to extend the chain.
        :return:
        """
        # construction and wire the journal to the
        # gossip layer.

        btm = BlockTreeManager()
        journal = None
        try:
            journal = Journal(consensus=test_mode_consensus,
                              block_store=btm.block_store.store,
                              block_cache=btm.block_cache,
                              block_sender=self.block_sender,
                              transaction_executor=self.txn_executor,
                              squash_handler=None)

            self.gossip.on_batch_received = journal.on_batch_received
            self.gossip.on_block_received = journal.on_block_received

            journal.start()

            # feed it a batch
            batch = Batch()
            journal.on_batch_received(batch)

            wait_until(lambda: self.block_sender.new_block is not None, 2)
            self.assertTrue(self.block_sender.new_block is not None)

            block = BlockWrapper(self.block_sender.new_block)
            journal.on_block_received(block)

            # wait for the chain_head to be updated.
            wait_until(lambda: btm.chain_head.identifier == block.identifier,
                       2)
            self.assertTrue(btm.chain_head.identifier == block.identifier)
        finally:
            if journal is not None:
                journal.stop()
    def test_max_block_size(self, mock_batch_injector_factory):
        '''
        Test block publisher obeys the block size limits
        '''

        mock_batch_injector_factory.create_injectors.return_value = []

        # Create a publisher that has a state view
        # with a batch limit
        addr, value = CreateSetting('sawtooth.publisher.max_batches_per_block',
                                    1)
        self.state_view_factory = MockStateViewFactory({addr: value})

        self.publisher = BlockPublisher(
            block_manager=self.block_tree_manager.block_manager,
            transaction_executor=MockTransactionExecutor(),
            transaction_committed=(
                self.block_tree_manager.block_store.has_transaction),
            batch_committed=self.block_tree_manager.block_store.has_batch,
            state_view_factory=self.state_view_factory,
            block_sender=self.block_sender,
            batch_sender=self.batch_sender,
            chain_head=self.block_tree_manager.chain_head.block,
            identity_signer=self.block_tree_manager.identity_signer,
            data_dir=None,
            config_dir=None,
            batch_observers=[],
            permission_verifier=self.permission_verifier,
            batch_injector_factory=mock_batch_injector_factory)

        self.assert_no_block_published()

        # receive batches, then try again (succeeding)
        self.receive_batches()

        # try to publish with no pending queue (failing)
        for i in range(self.batch_count):
            self.publish_block()
            self.assert_block_published()
            self.update_chain_head(BlockWrapper(self.result_block))
            self.verify_block([self.batches[i]])
Exemple #19
0
    def add_block(self, block_id, root='merkle_root'):
        head = self.chain_head
        if head:
            previous_id = head.header_signature
            num = head.header.block_num + 1
        else:
            previous_id = 'zzzzz'
            num = 0

        header = BlockHeader(block_num=num,
                             previous_block_id=previous_id,
                             signer_pubkey='pubkey',
                             batch_ids=[block_id],
                             consensus=b'consensus',
                             state_root_hash=root)

        block = Block(header=header.SerializeToString(),
                      header_signature=block_id,
                      batches=[_make_mock_batch(block_id)])

        self.update_chain([BlockWrapper(block)], [])
Exemple #20
0
    def generate_block(self,
                       previous_block=None,
                       add_to_store=False,
                       batch_count=0,
                       status=BlockStatus.Unknown,
                       invalid_consensus=False,
                       invalid_batch=False,
                       invalid_signature=False,
                       weight=1):

        previous = self._get_block(previous_block)
        if previous is None:
            previous = self._generate_genesis_block(_generate_id())
            previous.set_signature(_generate_id())
            previous_block_state = BlockState(block_wrapper=previous,
                                              weight=0,
                                              status=BlockStatus.Valid)
            self.block_store[previous.header_signature] = previous_block_state
            self.block_publisher.on_chain_updated(previous)

        while self.block_sender.new_block is None:
            self.block_publisher.on_batch_received(Batch())
            self.block_publisher.on_check_publish_block(True)

        block = self.block_sender.new_block
        self.block_sender.new_block = None

        header = BlockHeader()
        header.ParseFromString(block.header)
        block = BlockWrapper(header, block)

        if invalid_signature:
            block.set_signature("BAD")

        if add_to_store:
            block_state = BlockState(block_wrapper=block, weight=0)
            block_state.status = status
            self.block_store[block.header_signature] = block_state

        return block
Exemple #21
0
    def add_block(self, block, check_pending=False, nest=False):
        with self.lock:
            if check_pending:
                if len(self._pending_heads) == 0:
                    return
                #take from pending queue
                _, blkw = self._pending_heads.popitem()
            else:
                blkw = BlockWrapper(block)
            # new block from net

            while True:
                block = self._complete_block(blkw, nest)

                if block is not None:
                    # completed block - in sync mode genesis block
                    self.block_cache[block.header_signature] = blkw
                    LOGGER.debug("ADD BLOCK=%s.%s PROCESS INCOMPLETED",
                                 block.block_num, block.header_signature[:8])
                    """
                    PUT BLOCK into chain controller queue
                    """
                    self._on_block_received(blkw)
                    # take all rest blocks
                    #self._process_incomplete_blocks(block.header_signature)
                    self._incomplete_loop = True
                    self._process_incomplete_blocks(str(block.block_num), True)
                    self._incomplete_loop = False
                    LOGGER.debug(
                        "ADD INCOMPLETED BLOCKS DONE  nest_ready=%s pending=%s\n",
                        self._is_nests_ready(),
                        [bnum for bnum in self._pending_heads.keys()])
                    if len(self._pending_heads) == 0:
                        break
                    if not self._is_nests_ready():
                        break
                    _, blkw = self._pending_heads.popitem()

                else:
                    break
 def do_block_event_extractor():
     block_header = BlockHeader(block_num=85,
                                state_root_hash="0987654321fedcba",
                                previous_block_id="0000000000000000")
     block = BlockWrapper(
         Block(header_signature="abcdef1234567890",
               header=block_header.SerializeToString()))
     extractor = BlockEventExtractor(block)
     events = extractor.extract(
         [EventSubscription(event_type="sawtooth/block-commit")])
     assert events == [
         Event(event_type="sawtooth/block-commit",
               attributes=[
                   Event.Attribute(key="block_id",
                                   value="abcdef1234567890"),
                   Event.Attribute(key="block_num", value="85"),
                   Event.Attribute(key="state_root_hash",
                                   value="0987654321fedcba"),
                   Event.Attribute(key="previous_block_id",
                                   value="0000000000000000")
               ])
     ]
Exemple #23
0
    def on_check_publish_block(self, force=False):
        """
            Ask the consensus module if it is time to claim the candidate block
            if it is then, claim it and tell the world about it.
        :return:
        """
        try:
            with self._lock:
                if self._candidate_block is None and\
                        len(self._pending_batches) != 0:
                    self._candidate_block = self._build_block(self._chain_head)

                if self._candidate_block and \
                        (force or len(self._pending_batches) != 0) and \
                        self._consensus.check_publish_block(self.
                                                            _candidate_block):
                    candidate = self._candidate_block
                    self._candidate_block = None
                    candidate = self._finalize_block(candidate)
                    # if no batches are in the block, do not send it out
                    if len(candidate.batches) == 0:
                        LOGGER.info("No Valid batches added to block, " +
                                    " dropping %s",
                                    candidate.identifier[:8])
                        return
                    block = BlockWrapper(candidate.build_block())
                    self._block_cache[block.identifier] = block  # add the
                    # block to the cache, so we can build on top of it.
                    self._block_sender.send(block.block)

                    LOGGER.info("Claimed Block: %s", block)

                    # create a new block based on this one -- opportunistically
                    # assume the published block is the valid block.
                    self.on_chain_updated(block)
        # pylint: disable=broad-except
        except Exception as exc:
            LOGGER.exception(exc)
            LOGGER.critical("BlockPublisher thread exited.")
Exemple #24
0
    def on_block_received(self, block):
        with self._lock:
            if block.header_signature in self._block_store:
                # do we already have this block
                return
            header = BlockHeader()
            header.ParseFromString(block.header)
            block = BlockWrapper(header, block)

            LOGGER.debug('inserting block %s', block.header_signature)
            block_state = BlockState(block_wrapper=block, weight=0,
                                     status=BlockStatus.Unknown)
            self._block_store[block.header_signature] = block_state
            self._blocks_pending[block.header_signature] = []
            if block.header_signature in self._blocks_requested:
                # is it a requested block
                # route block to the validator that requested
                validator = self._blocks_requested.pop(block.header_signature)
                if validator.chain_head.block.header_signature != \
                        self._chain_head.block.header_signature:
                    # the head of the chain has changed start over
                    self._verify_block(validator.new_block)
                else:
                    self._executor.submit(validator.run)
            elif block.previous_block_id in self._blocks_processing or \
                    block.previous_block_id in self._blocks_pending:
                LOGGER.debug('in blocks pending: %s', block.header_signature)
                # if the previous block is being processed...put it in a wait
                # queue, Also need to check if previous block is in a wait
                # queue.
                pending_blocks = \
                    self._blocks_pending.get(block.previous_block_id,
                                             [])
                pending_blocks.append(block_state)
                self._blocks_pending[block.previous_block_id] = \
                    pending_blocks
            else:
                # schedule this block for validation.
                self._verify_block(block_state)
Exemple #25
0
    def initialize_block(self, previous_id, nest_colour=''):
        if previous_id:
            try:

                LOGGER.debug("ConsensusProxy:initialize_block head=%s",
                             previous_id.hex()[:8])
                #has = self._chain_controller.has_block(previous_id.hex())
                #previous_block1 = self._chain_controller.get_block_from_cache(previous_id.hex()) if has else None
                block = next(self._block_manager.get([previous_id.hex()]))
                previous_block = BlockWrapper(block=block,
                                              status=BlockStatus.Unknown)
                #LOGGER.debug("ConsensusProxy:initialize_block previous_block=(%s~%s)",type(previous_block),type(previous_block1))

            except StopIteration:
                raise UnknownBlock()

            self._block_publisher.initialize_block(previous_block, nest_colour)
            LOGGER.debug("ConsensusProxy:initialize_block DONE for head=%s ",
                         previous_id.hex()[:8])
        else:
            self._block_publisher.initialize_block(
                self._chain_controller.chain_head, nest_colour)
 def test_block_event_extractor(self):
     """Test that a sawtooth/block-commit event is generated correctly."""
     block_header = BlockHeader(block_num=85,
                                state_root_hash="0987654321fedcba",
                                previous_block_id="0000000000000000")
     block = BlockWrapper(
         Block(header_signature="abcdef1234567890",
               header=block_header.SerializeToString()))
     extractor = BlockEventExtractor(block)
     events = extractor.extract(
         [EventSubscription(event_type="sawtooth/block-commit")])
     self.assertEqual(events, [
         Event(event_type="sawtooth/block-commit",
               attributes=[
                   Event.Attribute(key="block_id",
                                   value="abcdef1234567890"),
                   Event.Attribute(key="block_num", value="85"),
                   Event.Attribute(key="state_root_hash",
                                   value="0987654321fedcba"),
                   Event.Attribute(key="previous_block_id",
                                   value="0000000000000000")
               ])
     ])
Exemple #27
0
    def on_check_publish_block(self, force=False):
        """Ask the consensus module if it is time to claim the candidate block
        if it is then, claim it and tell the world about it.
        :return:
            None
        """
        try:
            with self._lock:
                if self._chain_head is not None and\
                        self._candidate_block is None and\
                        len(self._pending_batches) != 0:
                    self._candidate_block = self._build_block(self._chain_head)
                if self._candidate_block and \
                        (force or len(self._pending_batches) != 0) and \
                        self._consensus.check_publish_block(self.
                                                            _candidate_block.
                                                            block_header):
                    candidate = self._candidate_block
                    self._candidate_block = None

                    if not self._finalize_block(candidate):
                        return

                    block = BlockWrapper(candidate.build_block())
                    self._block_cache[block.identifier] = block  # add the
                    # block to the cache, so we can build on top of it.
                    self._block_sender.send(block.block)

                    LOGGER.info("Claimed Block: %s", block)

                    # We built our candidate, disable processing until
                    # the chain head is updated.
                    self.on_chain_updated(None)
        # pylint: disable=broad-except
        except Exception as exc:
            LOGGER.critical("on_check_publish_block exception.")
            LOGGER.exception(exc)
Exemple #28
0
    def test_max_block_size(self):
        '''
        Test block publisher obeys the block size limits
        '''
        # Create a publisher that has a state view
        # with a batch limit
        addr, value = CreateSetting(
            'sawtooth.publisher.max_batches_per_block', 1)
        print('test', addr)
        self.state_view_factory = MockStateViewFactory(
            {addr: value})

        self.publisher = BlockPublisher(
            transaction_executor=MockTransactionExecutor(),
            block_cache=self.block_tree_manager.block_cache,
            state_view_factory=self.state_view_factory,
            block_sender=self.block_sender,
            batch_sender=self.batch_sender,
            squash_handler=None,
            chain_head=self.block_tree_manager.chain_head,
            identity_signing_key=self.block_tree_manager.identity_signing_key,
            data_dir=None,
            config_dir=None,
            permission_verifier=self.permission_verifier)

        self.assert_no_block_published()

        # receive batches, then try again (succeeding)
        self.receive_batches()

        # try to publish with no pending queue (failing)
        for i in range(self.batch_count):
            self.publish_block()
            self.assert_block_published()
            self.update_chain_head(BlockWrapper(self.result_block))
            self.verify_block([self.batches[i]])
Exemple #29
0
    def start(self, on_done):
        """
        Starts the genesis block creation process.  Will call the given
        `on_done` callback on successful completion.

        Args:
            on_done (function): a function called on completion

        Raises:
            InvalidGenesisStateError: raises this error if a genesis block is
                unable to be produced, or the resulting block-chain-id saved.
        """
        genesis_file = os.path.join(self._data_dir, 'genesis.batch')
        try:
            with open(genesis_file, 'rb') as batch_file:
                genesis_data = genesis_pb2.GenesisData()
                genesis_data.ParseFromString(batch_file.read())
            LOGGER.info('Producing genesis block from %s', genesis_file)
        except IOError:
            raise InvalidGenesisStateError(
                "Genesis File {} specified, but unreadable".format(
                    genesis_file))

        initial_state_root = self._context_manager.get_first_root()

        genesis_batches = [batch for batch in genesis_data.batches]
        if genesis_batches:
            scheduler = SerialScheduler(
                self._context_manager.get_squash_handler(),
                initial_state_root,
                always_persist=True)

            LOGGER.debug('Adding %s batches', len(genesis_data.batches))
            for batch in genesis_data.batches:
                scheduler.add_batch(batch)

            self._transaction_executor.execute(scheduler)

            scheduler.finalize()
            scheduler.complete(block=True)

        state_hash = initial_state_root
        for batch in genesis_batches:
            result = scheduler.get_batch_execution_result(
                batch.header_signature)
            if result is None or not result.is_valid:
                raise InvalidGenesisStateError(
                    'Unable to create genesis block, due to batch {}'.format(
                        batch.header_signature))
            if result.state_hash is not None:
                state_hash = result.state_hash
        LOGGER.debug('Produced state hash %s for genesis block.', state_hash)

        block_builder = self._generate_genesis_block()
        block_builder.add_batches(genesis_batches)
        block_builder.set_state_hash(state_hash)

        block_publisher = self._get_block_publisher(initial_state_root)
        if not block_publisher.initialize_block(block_builder.block_header):
            LOGGER.error('Consensus refused to initialize consensus block.')
            raise InvalidGenesisConsensusError(
                'Consensus refused to initialize genesis block.')

        if not block_publisher.finalize_block(block_builder.block_header):
            LOGGER.error('Consensus refused to finalize genesis block.')
            raise InvalidGenesisConsensusError(
                'Consensus refused to finalize genesis block.')

        self._sign_block(block_builder)

        block = block_builder.build_block()

        blkw = BlockWrapper(block=block, status=BlockStatus.Valid)

        LOGGER.info('Genesis block created: %s', blkw)

        self._completer.add_block(block)
        self._block_store.update_chain([blkw])

        self._chain_id_manager.save_block_chain_id(block.header_signature)

        LOGGER.debug('Deleting genesis data.')
        os.remove(genesis_file)

        if on_done is not None:
            on_done()
    def generate_block(self,
                       previous_block=None,
                       add_to_store=False,
                       add_to_cache=False,
                       batch_count=1,
                       batches=None,
                       status=BlockStatus.Unknown,
                       invalid_consensus=False,
                       invalid_batch=False,
                       invalid_signature=False,
                       weight=0):

        previous = self._get_block(previous_block)
        if previous is None:
            previous = self.chain_head

        header = BlockHeader(
            previous_block_id=previous.identifier,
            signer_public_key=self.identity_signer.get_public_key().as_hex(),
            block_num=previous.block_num + 1)

        block_builder = BlockBuilder(header)
        if batches:
            block_builder.add_batches(batches)

        if batch_count != 0:
            block_builder.add_batches(
                [self._generate_batch() for _ in range(batch_count)])

        if invalid_batch:
            block_builder.add_batches(
                [self._generate_batch_from_payload('BAD')])

        block_builder.set_state_hash('0' * 70)

        consensus = mock_consensus.BlockPublisher()
        consensus.finalize_block(block_builder.block_header, weight=weight)

        header_bytes = block_builder.block_header.SerializeToString()
        signature = self.identity_signer.sign(header_bytes)
        block_builder.set_signature(signature)

        block_wrapper = BlockWrapper(block_builder.build_block())

        if batches:
            block_wrapper.block.batches.extend(batches)

        if batch_count:
            block_wrapper.block.batches.extend(
                [self.generate_batch() for _ in range(batch_count)])

        if invalid_signature:
            block_wrapper.block.header_signature = "BAD"

        if invalid_consensus:
            block_wrapper.header.consensus = b'BAD'

        block_wrapper.status = status

        if add_to_cache:
            self.block_cache[block_wrapper.identifier] = block_wrapper

        if add_to_store:
            self.block_store[block_wrapper.identifier] = block_wrapper

        LOGGER.debug("Generated %s", dumps_block(block_wrapper))
        return block_wrapper