def inner_task(mocker, request):
    mocker.patch.object(IconScoreInnerTask, "_open")
    mocker.patch.object(IconScoreInnerTask, "_close")
    inner_task = IconScoreInnerTask(Mock(spec=IconConfig))
    inner_task._thread_flag = request.param
    icon_service_engine = Mock(spec=IconServiceEngine)
    inner_task._icon_service_engine = icon_service_engine

    return inner_task
Exemple #2
0
def _create_inner_task(
        prep_storage_open,
        prep_engine_open,
        iiss_storage_open,
        iiss_engine_open,
        load_last_tx_index,
        rc_db_from_path,
        db_factory_create_by_name,
        icx_engine_open,
        service_engine_load_builtin_scores,
        service_engine_init_global_value_by_governance_score):
    state_db = {}
    rc_db = {}

    def state_put(self, key, value):
        state_db[key] = value

    def state_get(self, key):
        return state_db.get(key)

    def rc_put(key, value):
        rc_db[key] = value

    def rc_get(key):
        return rc_db.get(key)

    context_db = Mock(spec=ContextDatabase)
    context_db.key_value_db = state_db
    context_db.get = state_get
    context_db.put = state_put

    iiss_mock_db = Mock(spec=KeyValueDatabase)
    iiss_mock_db.get = rc_get
    iiss_mock_db.put = rc_put

    db_factory_create_by_name.return_value = context_db
    rc_db_from_path.return_value = iiss_mock_db
    load_last_tx_index.return_value = 0
    inner_task = IconScoreInnerTask(IconConfig("", default_icon_config))

    # Patches create_by_name to pass creating DB
    db_factory_create_by_name.assert_called()
    icx_engine_open.assert_called()
    service_engine_load_builtin_scores.assert_called()
    service_engine_init_global_value_by_governance_score.assert_called()

    # Mocks _init_global_value_by_governance_score
    # to ignore initializing governance SCORE
    inner_task._icon_service_engine._init_global_value_by_governance_score = \
        service_engine_init_global_value_by_governance_score

    return inner_task
    def test_get_block_info_for_precommit_state(self):
        block_height = 10
        instant_block_hash = create_block_hash()
        block_hash = create_block_hash()

        # success case: when input prev write pre-commit data format, block_hash should be None
        prev_precommit_data_format = {
            ConstantKeys.BLOCK_HEIGHT: block_height,
            ConstantKeys.BLOCK_HASH: instant_block_hash
        }
        actual_block_height, actual_instant_block_hash, actual_block_hash = \
            IconScoreInnerTask._get_block_info_for_precommit_state(prev_precommit_data_format)

        self.assertEqual(block_height, actual_block_height)
        self.assertEqual(instant_block_hash, actual_instant_block_hash)
        self.assertIsNone(actual_block_hash)

        # success case: when input new write-pre-commit data format, block_hash should be hash
        new_precommit_data_format = {
            ConstantKeys.BLOCK_HEIGHT: block_height,
            ConstantKeys.OLD_BLOCK_HASH: instant_block_hash,
            ConstantKeys.NEW_BLOCK_HASH: block_hash
        }
        actual_block_height, actual_instant_block_hash, actual_block_hash = \
            IconScoreInnerTask._get_block_info_for_precommit_state(new_precommit_data_format)

        self.assertEqual(block_height, actual_block_height)
        self.assertEqual(instant_block_hash, actual_instant_block_hash)
        self.assertEqual(block_hash, actual_block_hash)

        # failure case: when input invalid data format, should raise key error
        invalid_precommit_data_format = {
            ConstantKeys.BLOCK_HEIGHT: block_height,
            ConstantKeys.OLD_BLOCK_HASH: instant_block_hash,
        }
        self.assertRaises(
            KeyError, IconScoreInnerTask._get_block_info_for_precommit_state,
            invalid_precommit_data_format)
    def setUp(self):
        self.icon_inner_task_open_patcher = patch(
            'iconservice.icon_inner_service.IconScoreInnerTask._open')
        self.icon_inner_task_close_patcher = patch(
            'iconservice.icon_inner_service.IconScoreInnerTask._close')
        _ = self.icon_inner_task_open_patcher.start()
        _ = self.icon_inner_task_close_patcher.start()

        IconScoreInnerTask._open = Mock()
        self.inner_task = IconScoreInnerTask(Mock(spec=IconConfig))
        icon_service_engine = Mock(spec=IconServiceEngine)
        self.inner_task._icon_service_engine = icon_service_engine

        block = {
            ConstantKeys.BLOCK_HEIGHT: hex(0),
            ConstantKeys.BLOCK_HASH: create_block_hash().hex(),
            ConstantKeys.TIMESTAMP: hex(0),
            ConstantKeys.PREV_BLOCK_HASH: create_block_hash().hex()
        }
        self.mocked_invoke_request = {"block": block, "transactions": []}
        self.mocked_write_precommit_request = {
            ConstantKeys.BLOCK_HEIGHT: hex(0),
            ConstantKeys.BLOCK_HASH: create_block_hash().hex()
        }
        self.mocked_query_request = {
            ConstantKeys.METHOD: "icx_call",
            ConstantKeys.PARAMS: {}
        }

        exception_msg = "non fatal exception"
        exception_list = [
            InvalidBaseTransactionException, IconServiceBaseException,
            Exception
        ]
        self.exception_list = list(
            map(lambda exception: exception(exception_msg), exception_list))
def generate_inner_task(db_factory_create_by_name, icx_engine_open,
                        service_engine_load_builtin_scores,
                        service_engine_init_global_value_by_governance_score):
    memory_db = {}

    def put(self, key, value):
        memory_db[key] = value

    def get(self, key):
        return memory_db.get(key)

    context_db = Mock(spec=ContextDatabase)
    context_db.get = get
    context_db.put = put

    db_factory_create_by_name.return_value = context_db
    inner_task = IconScoreInnerTask(IconConfig("", default_icon_config))

    # Patches create_by_name to pass creating DB
    db_factory_create_by_name.assert_called()
    icx_engine_open.assert_called()
    service_engine_load_builtin_scores.assert_called()
    service_engine_init_global_value_by_governance_score.assert_called()

    # Mocks get_balance so, it returns always 100 icx
    inner_task._icon_service_engine._icx_engine.get_balance = \
        Mock(return_value=100 * 10 ** 18)

    # Mocks _init_global_value_by_governance_score
    # to ignore initializing governance SCORE
    inner_task._icon_service_engine._init_global_value_by_governance_score = \
        service_engine_init_global_value_by_governance_score

    # Ignores icx transfer
    inner_task._icon_service_engine._icx_engine._transfer = Mock()

    # Ignores revision
    inner_task._icon_service_engine._set_revision_to_context = Mock()

    return inner_task
class TestIconInnerService(unittest.TestCase):
    def setUp(self):
        self.icon_inner_task_open_patcher = patch(
            'iconservice.icon_inner_service.IconScoreInnerTask._open')
        self.icon_inner_task_close_patcher = patch(
            'iconservice.icon_inner_service.IconScoreInnerTask._close')
        _ = self.icon_inner_task_open_patcher.start()
        _ = self.icon_inner_task_close_patcher.start()

        IconScoreInnerTask._open = Mock()
        self.inner_task = IconScoreInnerTask(Mock(spec=IconConfig))
        icon_service_engine = Mock(spec=IconServiceEngine)
        self.inner_task._icon_service_engine = icon_service_engine

        block = {
            ConstantKeys.BLOCK_HEIGHT: hex(0),
            ConstantKeys.BLOCK_HASH: create_block_hash().hex(),
            ConstantKeys.TIMESTAMP: hex(0),
            ConstantKeys.PREV_BLOCK_HASH: create_block_hash().hex()
        }
        self.mocked_invoke_request = {"block": block, "transactions": []}
        self.mocked_write_precommit_request = {
            ConstantKeys.BLOCK_HEIGHT: hex(0),
            ConstantKeys.BLOCK_HASH: create_block_hash().hex()
        }
        self.mocked_query_request = {
            ConstantKeys.METHOD: "icx_call",
            ConstantKeys.PARAMS: {}
        }

        exception_msg = "non fatal exception"
        exception_list = [
            InvalidBaseTransactionException, IconServiceBaseException,
            Exception
        ]
        self.exception_list = list(
            map(lambda exception: exception(exception_msg), exception_list))

    def tearDown(self):
        self.icon_inner_task_open_patcher.stop()
        self.icon_inner_task_close_patcher.stop()

    def test_get_block_info_for_precommit_state(self):
        block_height = 10
        instant_block_hash = create_block_hash()
        block_hash = create_block_hash()

        # success case: when input prev write pre-commit data format, block_hash should be None
        prev_precommit_data_format = {
            ConstantKeys.BLOCK_HEIGHT: block_height,
            ConstantKeys.BLOCK_HASH: instant_block_hash
        }
        actual_block_height, actual_instant_block_hash, actual_block_hash = \
            IconScoreInnerTask._get_block_info_for_precommit_state(prev_precommit_data_format)

        self.assertEqual(block_height, actual_block_height)
        self.assertEqual(instant_block_hash, actual_instant_block_hash)
        self.assertIsNone(actual_block_hash)

        # success case: when input new write-pre-commit data format, block_hash should be hash
        new_precommit_data_format = {
            ConstantKeys.BLOCK_HEIGHT: block_height,
            ConstantKeys.OLD_BLOCK_HASH: instant_block_hash,
            ConstantKeys.NEW_BLOCK_HASH: block_hash
        }
        actual_block_height, actual_instant_block_hash, actual_block_hash = \
            IconScoreInnerTask._get_block_info_for_precommit_state(new_precommit_data_format)

        self.assertEqual(block_height, actual_block_height)
        self.assertEqual(instant_block_hash, actual_instant_block_hash)
        self.assertEqual(block_hash, actual_block_hash)

        # failure case: when input invalid data format, should raise key error
        invalid_precommit_data_format = {
            ConstantKeys.BLOCK_HEIGHT: block_height,
            ConstantKeys.OLD_BLOCK_HASH: instant_block_hash,
        }
        self.assertRaises(
            KeyError, IconScoreInnerTask._get_block_info_for_precommit_state,
            invalid_precommit_data_format)

    def test_fatal_exception_catch_on_invoke(self):
        # invoke thread: invoke, write_precommit_state, remove_precommit_state

        # success case: when FatalException having been raised on invoke
        # should close the icon service after sending error response
        expected_error_msg = "fatal exception on invoke"
        expected_error_code = 32001

        def mocked_invoke(block, tx_requests, prev_block_generator,
                          prev_block_validators, prev_block_votes,
                          is_block_editable):
            raise FatalException(expected_error_msg)

        self.inner_task._icon_service_engine.invoke = mocked_invoke
        response = self.inner_task._invoke(self.mocked_invoke_request)
        assert expected_error_code, response['error']['code']
        assert expected_error_msg, response['error']['message']
        assert self.inner_task._close.called

        self.inner_task._close.reset_mock()

        # success case: when other exception having been raised, error response should be returned
        for exception in self.exception_list:
            expected_error_msg = exception.args[0]

            def mocked_invoke(block, tx_requests, prev_block_generator,
                              prev_block_validators, prev_block_votes,
                              is_block_editable):
                raise exception

            self.inner_task._icon_service_engine.invoke = mocked_invoke
            response = self.inner_task._invoke(self.mocked_invoke_request)
            assert expected_error_msg, response['error']['message']
            assert not self.inner_task._close.called
            self.inner_task._close.reset_mock()

    def test_fatal_exception_catch_on_write_precommit_state(self):
        # success case: when FatalException having been raised on write_precommit_state,
        # should close the icon service after sending error response
        expected_error_msg = "fatal exception on write_precommit_state"
        expected_error_code = 32001

        def mocked_write_precommit(block_height, instant_block_hash,
                                   block_hash):
            raise FatalException(expected_error_msg)

        self.inner_task._icon_service_engine.commit = mocked_write_precommit
        response = self.inner_task._write_precommit_state(
            self.mocked_write_precommit_request)
        assert expected_error_code, response['error']['code']
        assert expected_error_msg, response['error']['message']
        assert self.inner_task._close.called

        self.inner_task._close.reset_mock()

        # success case: when other exception having been raised, error response should be returned
        for exception in self.exception_list:
            expected_error_msg = exception.args[0]

            def mocked_write_precommit(block_height, instant_block_hash,
                                       block_hash):
                raise exception

            self.inner_task._icon_service_engine.invoke = mocked_write_precommit
            response = self.inner_task._invoke(
                self.mocked_write_precommit_request)
            assert expected_error_msg, response['error']['message']
            assert not self.inner_task._close.called
            self.inner_task._close.reset_mock()

    def test_fatal_exception_catch_on_query_thread(self):
        # query thread: query

        # success case: when FatalException having been raised on query, call (inner call),
        # should not close the icon service
        expected_error_msg = "fatal exception on query"
        expected_error_code = 32001

        def mocked_query(method, params):
            raise FatalException(expected_error_msg)

        self.inner_task._icon_service_engine.query = mocked_query
        response = self.inner_task._query(self.mocked_query_request)
        assert expected_error_code, response['error']['code']
        assert expected_error_msg, response['error']['message']
        assert not self.inner_task._close.called

        self.inner_task._close.reset_mock()

        # success case: when other exception having been raised, error response should be returned
        for exception in self.exception_list:
            expected_error_msg = exception.args[0]

            def mocked_query(method, params):
                raise exception

            self.inner_task._icon_service_engine.invoke = mocked_query
            response = self.inner_task._query(self.mocked_query_request)
            assert expected_error_msg, response['error']['message']
            assert not self.inner_task._close.called
            self.inner_task._close.reset_mock()