Check the block to see if it is complete and if it can be passed to
            the journal. If the block's predecessor is not in the block_manager
            the predecessor is requested and the current block is added to the
            the incomplete_block cache. If the block.batches and
            block.header.batch_ids are not the same length, the batch_id list
            is checked against the batch_cache to see if the batch_list can be
            built. If any batches are missing from the block and we do not have
            the batches in the batch_cache, they are requested. The block is
            then added to the incomplete_block cache. If we can complete the
            block, a new batch list is created in the correct order and added
            to the block. The block is now considered complete and is returned.
            If block.batches and block.header.batch_ids are the same length,
            the block's batch list needs to be in the same order as the
            block.header.batch_ids list. If the block has all of its expected
            batches but are not in the correct order, the batch list is rebuilt
            and added to the block. Once a block has the correct batch list it
            is added to the block_manager and is returned.

def _complete_block(self, block):
        """ Check the block to see if it is complete and if it can be passed to
            the journal. If the block's predecessor is not in the block_manager
            the predecessor is requested and the current block is added to the
            the incomplete_block cache. If the block.batches and
            block.header.batch_ids are not the same length, the batch_id list
            is checked against the batch_cache to see if the batch_list can be
            built. If any batches are missing from the block and we do not have
            the batches in the batch_cache, they are requested. The block is
            then added to the incomplete_block cache. If we can complete the
            block, a new batch list is created in the correct order and added
            to the block. The block is now considered complete and is returned.
            If block.batches and block.header.batch_ids are the same length,
            the block's batch list needs to be in the same order as the
            block.header.batch_ids list. If the block has all of its expected
            batches but are not in the correct order, the batch list is rebuilt
            and added to the block. Once a block has the correct batch list it
            is added to the block_manager and is returned.

        """

        if block.header_signature in self._block_manager:
            LOGGER.debug("Drop duplicate block: %s", block)
            return None

        # NOTE: We cannot assume that if the previous block _is_ in the block
        # manager, that it will still be in there when this block is complete.
        if block.previous_block_id not in self._block_manager:
            return self._request_previous_if_not_already_requested(block)

        # Check for same number of batch_ids and batches
        # If different starting building batch list, Otherwise there is a batch
        # that does not belong, block should be dropped.
        if len(block.batches) > len(block.header.batch_ids):
            LOGGER.debug("Block has extra batches. Dropping %s", block)
            return None

        # used to supplement batch_cache, contains batches already in block
        temp_batches = {}
        for batch in block.batches:
            temp_batches[batch.header_signature] = batch

        # The block is missing batches. Check to see if we can complete it.
        if len(block.batches) != len(block.header.batch_ids):
            building = True
            for batch_id in block.header.batch_ids:
                if batch_id not in self._batch_cache and \
                        batch_id not in temp_batches:
                    # Request all missing batches
                    if batch_id not in self._incomplete_blocks:
                        self._incomplete_blocks[batch_id] = [block]
                    elif block not in self._incomplete_blocks[batch_id]:
                        self._incomplete_blocks[batch_id] += [block]

                    # We have already requested the batch, do not do so again
                    if batch_id in self._requested:
                        return None
                    self._requested[batch_id] = None
                    self._gossip.broadcast_batch_by_batch_id_request(batch_id)
                    building = False

            # The block cannot be completed.
            if not building:
                return None

            batches = self._finalize_batch_list(block, temp_batches)
            del block.batches[:]
            # reset batches with full list batches
            block.batches.extend(batches)
            if block.header_signature in self._requested:
                del self._requested[block.header_signature]

            return self._put_or_request_if_missing_predecessor(block)

        batch_id_list = [x.header_signature for x in block.batches]
        # Check to see if batchs are in the correct order.
        if batch_id_list == list(block.header.batch_ids):
            if block.header_signature in self._requested:
                del self._requested[block.header_signature]

            return self._put_or_request_if_missing_predecessor(block)

        # Check to see if the block has all batch_ids and they can be put
        # in the correct order
        if sorted(batch_id_list) == sorted(list(block.header.batch_ids)):
            batches = self._finalize_batch_list(block, temp_batches)
            # Clear batches from block
            del block.batches[:]
            # reset batches with full list batches
            if batches is not None:
                block.batches.extend(batches)
            else:
                return None

            if block.header_signature in self._requested:
                del self._requested[block.header_signature]

            return self._put_or_request_if_missing_predecessor(block)

        LOGGER.debug("Block.header.batch_ids does not match set of "
                     "batches in block.batches Dropping %s", block)
        return None