Exemple #1
0
class TestIcxStorageForMalformedAddress(unittest.TestCase):
    def setUp(self):
        empty_address = MalformedAddress.from_string('')
        short_address_without_hx = MalformedAddress.from_string('12341234')
        short_address = MalformedAddress.from_string('hx1234512345')
        long_address_without_hx = MalformedAddress.from_string(
            'cf85fac2d0b507a2db9ce9526e6d01476f16a2d269f51636f9c4b2d512017faf')
        long_address = MalformedAddress.from_string(
            'hxcf85fac2d0b507a2db9ce9526e6d01476f16a2d269f51636f9c4b2d512017faf'
        )
        self.addresses = [
            empty_address, short_address_without_hx, short_address,
            long_address_without_hx, long_address
        ]

        self.db_name = 'icx.db'
        db = ContextDatabase.from_path(self.db_name)
        self.assertIsNotNone(db)

        self.storage = IcxStorage(db)

        self.factory = IconScoreContextFactory(max_size=1)
        context = self.factory.create(IconScoreContextType.DIRECT)
        self.context = context

    def tearDown(self):
        context = self.context
        self.storage.close(context)

        shutil.rmtree(self.db_name)

    def test_get_put_account(self):
        context = self.context
        account = Account()
        account.deposit(10**19)

        for address in self.addresses:
            account.address = address
            self.storage.put_account(context, account.address, account)

            account2 = self.storage.get_account(context, account.address)
            self.assertEqual(account, account2)

    def test_delete_account(self):
        context = self.context
        account = Account()

        for address in self.addresses:
            account.address = address
            self.storage.put_account(context, account.address, account)

            ret = self.storage.is_address_present(context, account.address)
            self.assertTrue(ret)

            self.storage.delete_account(context, account.address)

            ret = self.storage.is_address_present(context, account.address)
            self.assertFalse(ret)
Exemple #2
0
class TestIcxStorage(unittest.TestCase):
    def setUp(self):
        self.db_name = 'icx.db'
        self.address = create_address(AddressPrefix.EOA)
        db = ContextDatabase.from_path(self.db_name)
        self.assertIsNotNone(db)

        self.storage = IcxStorage(db)

        self.factory = IconScoreContextFactory(max_size=1)
        context = self.factory.create(IconScoreContextType.DIRECT)
        context.tx_batch = TransactionBatch()
        context.block_batch = BlockBatch()
        self.context = context

    def tearDown(self):
        context = self.context
        self.storage.delete_account(context, self.address)
        self.storage.close(context)

        shutil.rmtree(self.db_name)

    def test_get_put_account(self):
        context = self.context
        account = Account()
        account.address = create_address(AddressPrefix.EOA)
        account.deposit(10**19)

        self.storage.put_account(context, account.address, account)

        account2 = self.storage.get_account(context, account.address)
        self.assertEqual(account, account2)

    def test_delete_account(self):
        context = self.context
        account = Account()
        account.address = create_address(AddressPrefix.EOA)
        self.storage.put_account(context, account.address, account)

        ret = self.storage.is_address_present(context, account.address)
        self.assertTrue(ret)

        self.storage.delete_account(context, account.address)

        ret = self.storage.is_address_present(context, self.address)
        self.assertFalse(ret)
class TestIcxStorage(unittest.TestCase):
    def setUp(self):
        self.db_name = 'icx.db'
        self.address = create_address(AddressPrefix.EOA)
        db = ContextDatabase.from_path(self.db_name)
        self.assertIsNotNone(db)

        self.storage = IcxStorage(db)

        context = IconScoreContext(IconScoreContextType.DIRECT)
        context.tx_batch = TransactionBatch()
        context.block_batch = BlockBatch()
        self.context = context

    def tearDown(self):
        context = self.context
        self.storage.delete_account(context, self.address)
        self.storage.close(context)

        shutil.rmtree(self.db_name)

    def test_get_put_account(self):
        context = self.context
        account = Account()
        account.address = create_address(AddressPrefix.EOA)
        account.deposit(10**19)

        self.storage.put_account(context, account.address, account)

        account2 = self.storage.get_account(context, account.address)
        self.assertEqual(account, account2)

    def test_delete_account(self):
        context = self.context
        account = Account()
        account.address = create_address(AddressPrefix.EOA)
        self.storage.put_account(context, account.address, account)

        ret = self.storage.is_address_present(context, account.address)
        self.assertTrue(ret)

        self.storage.delete_account(context, account.address)

        ret = self.storage.is_address_present(context, self.address)
        self.assertFalse(ret)

    def test_get_put_text(self):
        context = self.context
        key_name = 'test_genesis'
        expected_text = json.dumps({
            'version':
            0,
            'address':
            str(create_address(AddressPrefix.EOA))
        })

        self.storage.put_text(context, key_name, expected_text)

        actual_stored_text = self.storage.get_text(context, key_name)
        self.assertEqual(expected_text, actual_stored_text)

    def test_get_put_total_supply(self):
        context = self.context
        current_total_supply = self.storage.get_total_supply(context)
        self.assertEqual(0, current_total_supply)

        putting_total_supply_amount = 1000
        self.storage.put_total_supply(context, putting_total_supply_amount)
        actual_stored_total_supply = self.storage.get_total_supply(context)
        self.assertEqual(putting_total_supply_amount,
                         actual_stored_total_supply)
Exemple #4
0
class TestIconScoreEngine(unittest.TestCase):
    _ROOT_SCORE_PATH = os.path.join(TEST_ROOT_PATH, 'score')
    _TEST_DB_PATH = 'tests/test_db/'

    def setUp(self):
        rmtree(self._ROOT_SCORE_PATH)
        rmtree(self._TEST_DB_PATH)

        archive_path = 'tests/sample/valid.zip'
        archive_path = os.path.join(TEST_ROOT_PATH, archive_path)
        zip_bytes = self.read_zipfile_as_byte(archive_path)
        install_path = os.path.join(TEST_ROOT_PATH, self._ROOT_SCORE_PATH)
        self.__unpack_zip_file(install_path, zip_bytes)

        db_path = os.path.join(TEST_ROOT_PATH, self._TEST_DB_PATH)
        ContextDatabaseFactory.open(
            db_path, ContextDatabaseFactory.Mode.SINGLE_DB)

        self.__ensure_dir(db_path)

        icx_db = ContextDatabaseFactory.create_by_name('icx_db')
        self.icx_storage = IcxStorage(icx_db)
        deploy_storage = IconScoreDeployStorage(self.icx_storage.db)
        deploy_engine = IconScoreDeployEngine()
        deploy_engine.open(self._ROOT_SCORE_PATH, deploy_storage)

        self.icon_score_loader = IconScoreLoader(self._ROOT_SCORE_PATH)

        IconScoreMapper.icon_score_loader = self.icon_score_loader
        IconScoreMapper.deploy_storage = deploy_storage
        self.icon_score_mapper = IconScoreMapper()

        self.engine = IconScoreEngine()
        self.engine.open(
            self.icx_storage,
            self.icon_score_mapper)

        self._from = create_address(AddressPrefix.EOA)
        self._icon_score_address = create_address(AddressPrefix.CONTRACT)

        self.factory = IconScoreContextFactory(max_size=1)
        IconScoreContext.icon_score_deploy_engine = deploy_engine
        self._context = self.factory.create(IconScoreContextType.DIRECT)
        self._context.msg = Message(self._from, 0)
        tx_hash = create_tx_hash()
        self._context.tx = Transaction(
            tx_hash, origin=create_address(AddressPrefix.EOA))
        block_hash = create_block_hash()
        self._context.block = Block(1, block_hash, 0, None)

    def tearDown(self):
        self.engine = None
        self.icx_storage.close(self._context)
        self.factory.destroy(self._context)
        ContextDatabaseFactory.close()

        remove_path = os.path.join(TEST_ROOT_PATH, self._ROOT_SCORE_PATH)
        IconScoreDeployer.remove_existing_score(remove_path)
        remove_path = os.path.join(TEST_ROOT_PATH, self._TEST_DB_PATH)
        IconScoreDeployer.remove_existing_score(remove_path)

    @staticmethod
    def read_zipfile_as_byte(archive_path: str) -> bytes:
        with open(archive_path, 'rb') as f:
            byte_data = f.read()
            return byte_data

    @staticmethod
    def __unpack_zip_file(install_path: str, data: bytes):
        file_info_generator = IconScoreDeployer._extract_files_gen(data)
        for name, file_info, parent_directory in file_info_generator:
            if not os.path.exists(os.path.join(install_path, parent_directory)):
                os.makedirs(os.path.join(install_path, parent_directory))
            with file_info as file_info_context,\
                    open(os.path.join(install_path, name), 'wb') as dest:
                contents = file_info_context.read()
                dest.write(contents)
        return True

    @staticmethod
    def __ensure_dir(file_path):
        directory = os.path.dirname(file_path)
        if not os.path.exists(directory):
            os.makedirs(directory)

    # FIXME
    # def test_install(self):
    #     proj_name = 'test_score'
    #     path = os.path.join(TEST_ROOT_PATH, 'tests/tmp/{}'.format(proj_name))
    #     install_data = {'contentType': 'application/tbears', 'content': path}
    #     self._engine.invoke(
    #         self._context, self._icon_score_address, 'install', install_data)
    #     self._engine.commit(self._context)

    def test_call_method(self):
        calldata = {'method': 'total_supply', 'params': {}}

        # proj_name = 'test_score'
        # path = os.path.join(TEST_ROOT_PATH, 'tests/tmp/{}'.format(proj_name))
        # install_data = {'contentType': 'application/tbears', 'content': path}
        # self._engine.invoke(
        #     self._context, self._icon_score_address, 'install', install_data)
        # self._engine.commit(self._context)
        context = self.factory.create(IconScoreContextType.QUERY)

        with self.assertRaises(InvalidParamsException) as cm:
            self.engine.query(
                context, self._icon_score_address, 'call', calldata)

        e = cm.exception
        self.assertEqual(ExceptionCode.INVALID_PARAMS, e.code)
        print(e)

        self.factory.destroy(context)
Exemple #5
0
class TestScoreDeployEngine(unittest.TestCase):
    _ROOT_SCORE_PATH = 'tests/score'
    _TEST_DB_PATH = 'tests/test_db'

    @classmethod
    def setUpClass(cls):
        db_path = os.path.join(PROJECT_ROOT_PATH, cls._TEST_DB_PATH)
        ContextDatabaseFactory.open(db_path,
                                    ContextDatabaseFactory.Mode.SINGLE_DB)

    @classmethod
    def tearDownClass(cls):
        ContextDatabaseFactory.close()

    def setUp(self):
        db_path = os.path.join(PROJECT_ROOT_PATH, self._TEST_DB_PATH)
        score_path = os.path.join(PROJECT_ROOT_PATH, self._ROOT_SCORE_PATH)

        self.score_path = score_path
        self._tx_index = 0

        self.__ensure_dir(db_path)
        self._icx_db = ContextDatabaseFactory.create_by_name(ICON_DEX_DB_NAME)
        self._icx_db.address = ICX_ENGINE_ADDRESS
        self._icx_storage = IcxStorage(self._icx_db)
        self._score_deploy_engine = isde.IconScoreDeployEngine()
        self._deploy_storage = IconScoreDeployStorage(self._icx_db)

        self._icon_score_mapper = IconScoreMapper()

        self.addr1 = create_address(AddressPrefix.EOA)
        self.addr2 = create_address(AddressPrefix.EOA)
        self.score_address = create_address(AddressPrefix.CONTRACT)
        self._score_deploy_engine.open(
            score_deploy_storage=self._deploy_storage)

        self.make_context()

    def tearDown(self):
        try:
            self._context = IconScoreContext(IconScoreContextType.DIRECT)
            self._icx_storage.close(self._context)
        finally:
            remove_path = os.path.join(PROJECT_ROOT_PATH,
                                       self._ROOT_SCORE_PATH)
            rmtree(remove_path)
            remove_path = os.path.join(PROJECT_ROOT_PATH, self._TEST_DB_PATH)
            rmtree(remove_path)

    def make_context(self):
        self._tx_index += 1
        self._context = IconScoreContext(IconScoreContextType.DIRECT)
        self._context.msg = Message(self.addr1, 0)

        self._context.tx = Transaction(create_tx_hash(), origin=self.addr1)
        self._context.block = Block(1, create_block_hash(), 0, None)
        self._context.icon_score_mapper = self._icon_score_mapper
        self._context.icx = IcxEngine()
        self.__step_counter_factory = IconScoreStepCounterFactory()
        self._context.revision = 0
        self._context.new_icon_score_mapper = {}
        self._step_counter: IconScoreStepCounter = \
            self.__step_counter_factory.create(IconScoreContextType.INVOKE)
        self._context.step_counter = self._step_counter
        self._context.icx.open(self._icx_storage)
        self._context.event_logs = Mock(spec=list)
        self._context.traces = Mock(spec=list)

    def _invoke_setUp(self, _is_audit_needed: bool):
        self._score_deploy_engine._is_audit_needed = Mock(
            return_value=_is_audit_needed)
        self._score_deploy_engine.deploy = Mock()
        self._deploy_storage.put_deploy_info_and_tx_params = Mock()

    def _is_audit_needed_setUp(self, revision: int, get_owner,
                               is_service_flag_on: bool):
        self._context.revision = revision
        IconScoreContextUtil.is_service_flag_on.return_value = is_service_flag_on
        IconScoreContextUtil.get_owner.return_value = get_owner

    def _deploy_setUp(self, get_deploy_tx_params=None):
        self._score_deploy_engine._score_deploy = Mock()
        self._deploy_storage.update_score_info = Mock()
        self._deploy_storage.get_deploy_tx_params = Mock(
            return_value=get_deploy_tx_params)

    def _score_deploy_setUp(self, legacy_tbears_mode: bool = False):
        self._score_deploy_engine._on_deploy = Mock()
        self._context.legacy_tbears_mode = legacy_tbears_mode

    # case when icon_score_address is in (None, ZERO_ADDRESS)
    @patch_several(VALIDATE_SCORE_BLACKLIST_PATCHER,
                   IS_SERVICE_FLAG_ON_PATCHER, VALIDATE_DEPLOYER)
    def test_invoke_case1(self):
        self._invoke_setUp(True)

        with self.assertRaises(AssertionError):
            self._score_deploy_engine.invoke(self._context,
                                             GOVERNANCE_SCORE_ADDRESS,
                                             ZERO_SCORE_ADDRESS, {})
        IconScoreContextUtil.validate_score_blacklist.assert_not_called()
        IconScoreContextUtil.validate_deployer.assert_not_called()
        self._deploy_storage.put_deploy_info_and_tx_params.assert_not_called()
        self._score_deploy_engine._is_audit_needed.assert_not_called()
        self._score_deploy_engine.deploy.assert_not_called()

        with self.assertRaises(AssertionError):
            self._score_deploy_engine.invoke(self._context,
                                             GOVERNANCE_SCORE_ADDRESS, None,
                                             {})
        IconScoreContextUtil.validate_score_blacklist.assert_not_called()
        IconScoreContextUtil.validate_deployer.assert_not_called()
        self._deploy_storage.put_deploy_info_and_tx_params.assert_not_called()
        self._score_deploy_engine._is_audit_needed.assert_not_called()
        self._score_deploy_engine.deploy.assert_not_called()

    # case when deployer_white_list flag on, ignore audit
    @patch_several(VALIDATE_SCORE_BLACKLIST_PATCHER,
                   IS_SERVICE_FLAG_ON_PATCHER, VALIDATE_DEPLOYER)
    def test_invoke_case2(self):
        self._invoke_setUp(False)

        self._score_deploy_engine.invoke(self._context, ZERO_SCORE_ADDRESS,
                                         GOVERNANCE_SCORE_ADDRESS, {})

        IconScoreContextUtil.validate_score_blacklist.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.validate_deployer.assert_called_with(
            self._context, self._context.tx.origin)
        self._deploy_storage.put_deploy_info_and_tx_params.\
            assert_called_with(self._context, GOVERNANCE_SCORE_ADDRESS, DeployType.INSTALL, self._context.tx.origin,
                               self._context.tx.hash, {})
        self._score_deploy_engine.deploy.assert_called_with(
            self._context, self._context.tx.hash)

    # case when deployer_white_list flag on, audit
    @patch_several(VALIDATE_SCORE_BLACKLIST_PATCHER,
                   IS_SERVICE_FLAG_ON_PATCHER, VALIDATE_DEPLOYER)
    def test_invoke_case3(self):
        self._invoke_setUp(True)

        self._score_deploy_engine.invoke(self._context, ZERO_SCORE_ADDRESS,
                                         GOVERNANCE_SCORE_ADDRESS, {})

        IconScoreContextUtil.validate_score_blacklist.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.validate_deployer.assert_called_with(
            self._context, self._context.tx.origin)
        self._deploy_storage.put_deploy_info_and_tx_params.\
            assert_called_with(self._context, GOVERNANCE_SCORE_ADDRESS, DeployType.INSTALL, self._context.tx.origin,
                               self._context.tx.hash, {})
        self._score_deploy_engine.deploy.assert_not_called()

    # case when deployer_white_list flag off, audit
    @patch_several(VALIDATE_SCORE_BLACKLIST_PATCHER,
                   IS_SERVICE_FLAG_ON_PATCHER, VALIDATE_DEPLOYER)
    def test_invoke_case4(self):
        self._invoke_setUp(False)

        self._score_deploy_engine.invoke(self._context, ZERO_SCORE_ADDRESS,
                                         GOVERNANCE_SCORE_ADDRESS, {})

        IconScoreContextUtil.validate_score_blacklist.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.validate_deployer.assert_called_with(
            self._context, self._context.tx.origin)
        self._deploy_storage.put_deploy_info_and_tx_params. \
            assert_called_with(self._context, GOVERNANCE_SCORE_ADDRESS, DeployType.INSTALL, self._context.tx.origin,
                               self._context.tx.hash, {})
        self._score_deploy_engine.deploy.assert_called_with(
            self._context, self._context.tx.hash)

    # case when deployer_white_list flag off, audit on
    @patch_several(VALIDATE_SCORE_BLACKLIST_PATCHER,
                   IS_SERVICE_FLAG_ON_PATCHER, VALIDATE_DEPLOYER)
    def test_invoke_case5(self):
        self._invoke_setUp(True)

        self._score_deploy_engine.invoke(self._context, ZERO_SCORE_ADDRESS,
                                         GOVERNANCE_SCORE_ADDRESS, {})

        IconScoreContextUtil.validate_score_blacklist.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.validate_deployer.assert_called_with(
            self._context, self._context.tx.origin)
        self._score_deploy_engine.deploy.assert_not_called()

    # case when revision0, owner, audit false
    @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER)
    def test_is_audit_needed_case1(self):
        self._is_audit_needed_setUp(0, self.addr1, False)

        result = self._score_deploy_engine._is_audit_needed(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.get_owner.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.is_service_flag_on.assert_called_with(
            self._context, IconServiceFlag.AUDIT)
        self.assertFalse(result)

    # case when revision0, owner x, audit false
    @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER)
    def test_is_audit_needed_case2(self):
        self._is_audit_needed_setUp(0, self.addr2, False)

        result = self._score_deploy_engine._is_audit_needed(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.get_owner.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.is_service_flag_on.assert_called_with(
            self._context, IconServiceFlag.AUDIT)
        self.assertFalse(result)

    # case when revision0, owner, audit true
    @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER)
    def test_is_audit_needed_case3(self):
        self._is_audit_needed_setUp(0, self.addr1, True)

        result = self._score_deploy_engine._is_audit_needed(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.get_owner.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.is_service_flag_on.assert_called_with(
            self._context, IconServiceFlag.AUDIT)
        self.assertTrue(result)

    # case when revision0, owner x, audit true
    @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER)
    def test_is_audit_needed_case4(self):
        self._is_audit_needed_setUp(0, self.addr2, True)

        result = self._score_deploy_engine._is_audit_needed(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.get_owner.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.is_service_flag_on.assert_called_with(
            self._context, IconServiceFlag.AUDIT)
        self.assertTrue(result)

    # case when revision2, transaction requested by owner, audit true, system_score
    @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER)
    def test_is_audit_needed_case5(self):
        self._is_audit_needed_setUp(2, self.addr1, True)

        result = self._score_deploy_engine._is_audit_needed(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.get_owner.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.is_service_flag_on.assert_called_with(
            self._context, IconServiceFlag.AUDIT)
        self.assertFalse(result)

    # case when revision2, transaction requested by stranger, audit true, system_score
    @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER)
    def test_is_audit_needed_case6(self):
        self._is_audit_needed_setUp(2, self.addr2, True)

        result = self._score_deploy_engine._is_audit_needed(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.get_owner.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.is_service_flag_on.assert_called_with(
            self._context, IconServiceFlag.AUDIT)
        self.assertTrue(result)

    # case when revision2, transaction requested by owner, audit false, system_score
    @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER)
    def test_is_audit_needed_case7(self):
        self._is_audit_needed_setUp(2, self.addr1, False)

        result = self._score_deploy_engine._is_audit_needed(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.get_owner.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.is_service_flag_on.assert_called_with(
            self._context, IconServiceFlag.AUDIT)
        self.assertFalse(result)

    # case when revision2, transaction requested by stranger, audit false, system_score
    @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER)
    def test_is_audit_needed_case8(self):
        self._is_audit_needed_setUp(2, self.addr1, False)

        result = self._score_deploy_engine._is_audit_needed(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.get_owner.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS)
        IconScoreContextUtil.is_service_flag_on.assert_called_with(
            self._context, IconServiceFlag.AUDIT)
        self.assertFalse(result)

    # case when revision2, transaction requested by owner, audit true, normal_score
    @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER)
    def test_is_audit_needed_case9(self):
        self._is_audit_needed_setUp(2, self.addr1, True)

        result = self._score_deploy_engine._is_audit_needed(
            self._context, self.score_address)
        IconScoreContextUtil.get_owner.assert_called_with(
            self._context, self.score_address)
        IconScoreContextUtil.is_service_flag_on.assert_called_with(
            self._context, IconServiceFlag.AUDIT)
        self.assertTrue(result)

    # case when revision2, transaction requested by stranger, audit true, normal_score
    @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER)
    def test_is_audit_needed_case10(self):
        self._is_audit_needed_setUp(2, self.addr2, True)

        result = self._score_deploy_engine._is_audit_needed(
            self._context, self.score_address)
        IconScoreContextUtil.get_owner.assert_called_with(
            self._context, self.score_address)
        IconScoreContextUtil.is_service_flag_on.assert_called_with(
            self._context, IconServiceFlag.AUDIT)
        self.assertTrue(result)

    # case when revision2, transaction requested by owner, audit false, normal_score
    @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER)
    def test_is_audit_needed_case11(self):
        self._is_audit_needed_setUp(2, self.addr1, False)

        result = self._score_deploy_engine._is_audit_needed(
            self._context, self.score_address)
        IconScoreContextUtil.get_owner.assert_called_with(
            self._context, self.score_address)
        IconScoreContextUtil.is_service_flag_on.assert_called_with(
            self._context, IconServiceFlag.AUDIT)
        self.assertFalse(result)

    # case when revision2, transaction requested by stranger, audit false, normal_score
    @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER)
    def test_is_audit_needed_case12(self):
        self._is_audit_needed_setUp(2, self.addr1, False)

        result = self._score_deploy_engine._is_audit_needed(
            self._context, self.score_address)
        IconScoreContextUtil.get_owner.assert_called_with(
            self._context, self.score_address)
        IconScoreContextUtil.is_service_flag_on.assert_called_with(
            self._context, IconServiceFlag.AUDIT)
        self.assertFalse(result)

    # case when tx_param is None
    @patch_several(GET_DEPLOY_TX_PARAMS_PATCHER)
    def test_deploy_case1(self):
        self._deploy_setUp()

        with self.assertRaises(InvalidParamsException) as e:
            self._score_deploy_engine.deploy(self._context,
                                             self._context.tx.hash)

        self._deploy_storage.get_deploy_tx_params.assert_called_with(
            self._context, self._context.tx.hash)
        self.assertEqual(e.exception.code, ExceptionCode.INVALID_PARAMETER)
        self._score_deploy_engine._score_deploy.assert_not_called()
        self._score_deploy_engine._score_deploy_storage.update_score_info.assert_not_called(
        )

    # case when tx_param is not None
    @patch_several(GET_DEPLOY_TX_PARAMS_PATCHER)
    def test_deploy_case2(self):
        tx_params = Mock(spec=IconScoreDeployTXParams)
        tx_params.configure_mock(score_address=GOVERNANCE_SCORE_ADDRESS)
        self._deploy_setUp(tx_params)

        self._score_deploy_engine.deploy(self._context, self._context.tx.hash)

        self._score_deploy_engine._score_deploy.assert_called_with(
            self._context, tx_params)
        self._score_deploy_engine._score_deploy_storage.\
            update_score_info.assert_called_with(self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash)

    # test for tbears mode, legacy_tbears_mode is True
    def test_score_deploy_case1(self):
        self._score_deploy_setUp(True)
        tx_params = Mock(spec=IconScoreDeployTXParams)
        tx_params.configure_mock(deploy_data={
            'contentType': 'application/tbears',
            'content': '0x1234'
        })

        self._score_deploy_engine._score_deploy(self._context, tx_params)

        self._score_deploy_engine._on_deploy.assert_called_with(
            self._context, tx_params)

    # test for tbears mode, and legacy_tbears_mode is False
    def test_score_deploy_case2(self):
        tx_params = Mock(spec=IconScoreDeployTXParams)
        tx_params.configure_mock(deploy_data={
            'contentType': 'application/tbears',
            'content': '0x1234'
        })
        self._score_deploy_setUp()

        with self.assertRaises(InvalidParamsException) as e:
            self._score_deploy_engine._score_deploy(self._context, tx_params)
        self.assertEqual(e.exception.code, ExceptionCode.INVALID_PARAMETER)
        self.assertEqual(e.exception.message,
                         f"Invalid contentType: application/tbears")
        self._score_deploy_engine._on_deploy.assert_not_called()

    # test for zip mode
    def test_score_deploy_case3(self):
        tx_params = Mock(spec=IconScoreDeployTXParams)
        tx_params.configure_mock(deploy_data={
            'contentType': 'application/zip',
            'content': '0x1234'
        })
        self._score_deploy_setUp()

        self._score_deploy_engine._score_deploy(self._context, tx_params)

        self._score_deploy_engine._on_deploy.assert_called_with(
            self._context, tx_params)

    # test for wrong contentType
    def test_score_deploy_case4(self):
        self._score_deploy_setUp()
        tx_params = Mock(spec=IconScoreDeployTXParams)
        tx_params.configure_mock(deploy_data={
            'contentType': 'wrong/content',
            'content': '0x1234'
        })

        with self.assertRaises(InvalidParamsException) as e:
            self._score_deploy_engine._score_deploy(self._context, tx_params)
        self.assertEqual(e.exception.code, ExceptionCode.INVALID_PARAMETER)
        self.assertEqual(e.exception.message,
                         f'Invalid contentType: wrong/content')
        self._score_deploy_engine._on_deploy.assert_not_called()

    # Case when deploy_info is not None, zip, revision0, score validator flag False, SCORE is not None
    @patch_several(VALIDATE_PACKAGE_PATCHER)
    def test_on_deploy(self):
        mock_score = MockScore()
        mock_score.owner = self.addr1
        deploy_params = {"a": 1}
        deploy_data = {"params": deploy_params}
        deploy_info = Mock(spec=IconScoreDeployInfo)
        deploy_type = 'deploy_type'
        next_tx_hash = b'\00\01' * 16
        deploy_info.configure_mock(next_tx_hash=next_tx_hash)
        tx_params = Mock(spec=IconScoreDeployTXParams)
        tx_params.configure_mock(score_address=self.score_address,
                                 deploy_data=deploy_data,
                                 deploy_type=deploy_type,
                                 params=deploy_params)

        backup_msg, backup_tx = self._context.msg, self._context.tx

        self._score_deploy_engine._write_score_to_filesystem = Mock()
        score_info = Mock()
        score_info.configure_mock(get_score=Mock(return_value=mock_score))
        self._score_deploy_engine._create_score_info = Mock(
            return_value=score_info)
        self._deploy_storage.get_deploy_info = Mock(return_value=deploy_info)
        self._score_deploy_engine._initialize_score = Mock()

        self._score_deploy_engine._on_deploy(self._context, tx_params)

        self._deploy_storage.get_deploy_info.assert_called_with(
            self._context, self.score_address)
        self._score_deploy_engine._write_score_to_filesystem.assert_called_with(
            self._context, self.score_address, next_tx_hash, deploy_data)
        IconScoreContextUtil.validate_score_package.assert_called_with(
            self._context, self.score_address, next_tx_hash)
        self._score_deploy_engine._create_score_info.assert_called_with(
            self._context, self.score_address, next_tx_hash)
        score_info.get_score.assert_called_with(self._context.revision)
        self._score_deploy_engine._initialize_score.assert_called_with(
            deploy_type, mock_score, deploy_params)

        self.assertEqual(self._context.msg, backup_msg)
        self.assertEqual(self._context.tx, backup_tx)

    # tbears mode
    def test_write_score_to_filesystem_case1(self):
        content = '0x1234'
        deploy_data = {'contentType': 'application/tbears', 'content': content}
        self._score_deploy_engine._write_score_to_score_deploy_path_on_tbears_mode = Mock(
        )

        self._score_deploy_engine._write_score_to_filesystem(
            self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash,
            deploy_data)
        self._score_deploy_engine._write_score_to_score_deploy_path_on_tbears_mode.\
            assert_called_with(self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, content)

    # normal mode
    def test_write_score_to_filesystem_case2(self):
        content = '0x1234'
        deploy_data = {'contentType': 'application/zip', 'content': content}
        self._score_deploy_engine._write_score_to_score_deploy_path = Mock()

        self._score_deploy_engine._write_score_to_filesystem(
            self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash,
            deploy_data)
        self._score_deploy_engine._write_score_to_score_deploy_path. \
            assert_called_with(self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, content)

    # case when current_score_info is None
    @patch_several(GET_SCORE_INFO_PATCHER, CREATE_SCORE_INFO_PATCHER)
    def test_create_score_info_case1(self):
        IconScoreContextUtil.get_score_info.return_value = None

        self._score_deploy_engine._create_score_info(self._context,
                                                     GOVERNANCE_SCORE_ADDRESS,
                                                     self._context.tx.hash)
        IconScoreContextUtil.create_score_info.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash,
            None)

    # case when current_score_info is not None
    @patch_several(GET_SCORE_INFO_PATCHER, CREATE_SCORE_INFO_PATCHER)
    def test_create_score_info_case2(self):
        db = 'db'
        score_info_mock = Mock()
        score_info_mock.configure_mock(score_db=db)
        IconScoreContextUtil.get_score_info.return_value = score_info_mock

        self._score_deploy_engine._create_score_info(self._context,
                                                     GOVERNANCE_SCORE_ADDRESS,
                                                     self._context.tx.hash)
        IconScoreContextUtil.create_score_info.assert_called_with(
            self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, db)

    @patch_several(GET_SCORE_PATH_PATCHER, GET_SCORE_DEPLOY_PATH_PATCHER,
                   SYMLINK_PATCHER, MAKE_DIR_PATCHER)
    def test_write_score_to_score_deploy_path_on_tbears_mode(self):
        score_deploy_path = 'score_deploy_path'
        isde.get_score_deploy_path.return_value = score_deploy_path
        score_path = 'score_path'
        isde.get_score_path.return_value = score_path

        self._score_deploy_engine._write_score_to_score_deploy_path_on_tbears_mode\
            (self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, None)

        isde.get_score_path.assert_called_with(self._context.score_root_path,
                                               GOVERNANCE_SCORE_ADDRESS)
        os.makedirs.assert_called_with(score_path, exist_ok=True)
        os.symlink.assert_called_with(None,
                                      score_deploy_path,
                                      target_is_directory=True)

    # case when revision3
    @patch_several(DEPLOY_PATCHER, REMOVE_PATH_PATCHER,
                   GET_SCORE_DEPLOY_PATH_PATCHER, OS_PATH_JOIN_PATCHER)
    def test_write_score_to_score_deploy_path_case1(self):
        self._context.revision = 3
        score_path = 'score_path'
        score_deploy_path = 'score_deploy_path'
        isde.get_score_deploy_path.return_value = 'score_deploy_path'
        os.path.join.return_value = score_path
        self._score_deploy_engine._write_score_to_score_deploy_path(
            self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash,
            None)

        isde.get_score_deploy_path.assert_called_with(
            self._context.score_root_path, GOVERNANCE_SCORE_ADDRESS,
            self._context.tx.hash)
        os.path.join.assert_called_with(
            self._context.score_root_path,
            GOVERNANCE_SCORE_ADDRESS.to_bytes().hex(),
            f"0x{self._context.tx.hash.hex()}")
        isde.remove_path.assert_called_with(score_path)
        IconScoreDeployer.deploy.assert_called_with(score_deploy_path, None, 3)

    # case when revision2
    @patch_several(DEPLOY_PATCHER, REMOVE_PATH_PATCHER,
                   GET_SCORE_DEPLOY_PATH_PATCHER, OS_PATH_JOIN_PATCHER)
    def test_write_score_to_score_deploy_path_case1(self):
        self._context.revision = 2
        score_path = 'score_path'
        score_deploy_path = 'score_deploy_path'
        isde.get_score_deploy_path.return_value = 'score_deploy_path'
        os.path.join.return_value = score_path
        self._score_deploy_engine._write_score_to_score_deploy_path(
            self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash,
            None)

        isde.get_score_deploy_path.assert_called_with(
            self._context.score_root_path, GOVERNANCE_SCORE_ADDRESS,
            self._context.tx.hash)
        os.path.join.assert_not_called()
        isde.remove_path.assert_not_called()
        IconScoreDeployer.deploy.assert_called_with(score_deploy_path, None, 2)

    # case when revision0
    @patch_several(DEPLOY_PATCHER, DEPLOY_LEGACY_PATCHER, REMOVE_PATH_PATCHER,
                   GET_SCORE_DEPLOY_PATH_PATCHER, OS_PATH_JOIN_PATCHER)
    def test_write_score_to_score_deploy_path_case1(self):
        score_path = 'score_path'
        score_deploy_path = 'score_deploy_path'
        isde.get_score_deploy_path.return_value = 'score_deploy_path'
        os.path.join.return_value = score_path
        self._score_deploy_engine._write_score_to_score_deploy_path(
            self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash,
            None)

        isde.get_score_deploy_path.assert_called_with(
            self._context.score_root_path, GOVERNANCE_SCORE_ADDRESS,
            self._context.tx.hash)
        os.path.join.assert_not_called()
        isde.remove_path.assert_not_called()
        IconScoreDeployer.deploy.assert_not_called()
        IconScoreDeployer.deploy_legacy.assert_called_with(
            score_deploy_path, None)

    # case on_install
    @patch_several(MAKE_ANNOTATIONS_FROM_METHOD_PATCHER,
                   CONVERT_DATA_PARAMS_PATCHER)
    def test_initialize_score_case1(self):
        mock_score = MockScore()
        on_install = Mock()
        mock_score.on_install = on_install
        deploy_type = DeployType.INSTALL
        params = {"param1": '0x1', "param2": "string"}

        self._score_deploy_engine._initialize_score(deploy_type, mock_score,
                                                    params)
        TypeConverter.make_annotations_from_method.assert_called_with(
            on_install)
        TypeConverter.convert_data_params.assert_called_with(
            'annotations', params)
        on_install.assert_called_with(**params)

    # case on_update
    @patch_several(MAKE_ANNOTATIONS_FROM_METHOD_PATCHER,
                   CONVERT_DATA_PARAMS_PATCHER)
    def test_initialize_score_case2(self):
        mock_score = MockScore()
        on_update = Mock()
        mock_score.on_update = on_update
        deploy_type = DeployType.UPDATE
        params = {"param1": '0x1', "param2": "string"}

        self._score_deploy_engine._initialize_score(deploy_type, mock_score,
                                                    params)
        TypeConverter.make_annotations_from_method.assert_called_with(
            on_update)
        TypeConverter.convert_data_params.assert_called_with(
            'annotations', params)
        on_update.assert_called_with(**params)

    # case strange method name
    @patch_several(MAKE_ANNOTATIONS_FROM_METHOD_PATCHER,
                   CONVERT_DATA_PARAMS_PATCHER)
    def test_initialize_score_case3(self):
        mock_score = MockScore()
        on_strange = Mock()
        mock_score.on_install = on_strange
        deploy_type = "strange"
        params = {"param1": '0x1', "param2": "string"}

        with self.assertRaises(InvalidParamsException) as e:
            self._score_deploy_engine._initialize_score(
                deploy_type, mock_score, params)

        self.assertEqual(e.exception.code, ExceptionCode.INVALID_PARAMETER)
        self.assertEqual(e.exception.message,
                         f"Invalid deployType: {deploy_type}")
        TypeConverter.make_annotations_from_method.assert_not_called()
        TypeConverter.convert_data_params.assert_not_called()
        on_strange.assert_not_called()

    @staticmethod
    def __ensure_dir(dir_path):
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)
Exemple #6
0
class TestScoreDeployEngine(unittest.TestCase):
    _ROOT_SCORE_PATH = 'tests/score'
    _TEST_DB_PATH = 'tests/test_db'

    @classmethod
    def setUpClass(cls):
        db_path = os.path.join(TEST_ROOT_PATH, cls._TEST_DB_PATH)
        ContextDatabaseFactory.open(db_path,
                                    ContextDatabaseFactory.Mode.SINGLE_DB)

    @classmethod
    def tearDownClass(cls):
        ContextDatabaseFactory.close()

    def setUp(self):
        db_path = os.path.join(TEST_ROOT_PATH, self._TEST_DB_PATH)
        score_path = os.path.join(TEST_ROOT_PATH, self._ROOT_SCORE_PATH)

        self._tx_index = 0

        self.__ensure_dir(db_path)
        self._icx_db = ContextDatabaseFactory.create_by_name('icon_dex')
        self._icx_db.address = ICX_ENGINE_ADDRESS
        self._icx_storage = IcxStorage(self._icx_db)
        self._score_deploy_engine = IconScoreDeployEngine()
        self._deploy_storage = IconScoreDeployStorage(self._icx_db)

        self._icon_score_loader = IconScoreLoader(score_path)
        self._icon_score_mapper = IconScoreMapper()

        self._addr1 = create_address(AddressPrefix.EOA)
        self._score_deploy_engine.open(
            score_root_path=score_path,
            icon_deploy_storage=self._deploy_storage)

        self._factory = IconScoreContextFactory(max_size=1)
        self.make_context()

    def tearDown(self):
        try:
            self._context = self._factory.create(IconScoreContextType.DIRECT)
            self._factory.destroy(self._context)
            self._icx_storage.close(self._context)
        finally:
            remove_path = os.path.join(TEST_ROOT_PATH, self._ROOT_SCORE_PATH)
            rmtree(remove_path)
            remove_path = os.path.join(TEST_ROOT_PATH, self._TEST_DB_PATH)
            rmtree(remove_path)

    def make_context(self):
        self._tx_index += 1
        self._context = self._factory.create(IconScoreContextType.DIRECT)
        self._context.msg = Message(self._addr1, 0)

        self._context.tx = Transaction(create_tx_hash(), origin=self._addr1)
        self._context.block = Block(1, create_block_hash(), 0, None)
        self._context.icon_score_mapper = self._icon_score_mapper
        self._context.icx = IcxEngine()
        self.__step_counter_factory = IconScoreStepCounterFactory()
        self._step_counter: IconScoreStepCounter = \
            self.__step_counter_factory.create(100)
        self._context.step_counter = self._step_counter
        self._context.icx.open(self._icx_storage)
        self._context.event_logs = Mock(spec=list)
        self._context.traces = Mock(spec=list)

    @staticmethod
    def __ensure_dir(dir_path):
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)