def test_revert(self, mocker):
        mocker.patch.object(IconServiceEngine, "_charge_transaction_fee")
        mocker.patch.object(IconScoreEngine, "invoke")

        context = ContextContainer._get_context()

        icon_service_engine = IconServiceEngine()
        icon_service_engine._icx_engine = Mock(spec=IcxEngine)
        icon_service_engine._icon_score_deploy_engine = \
            Mock(spec=DeployEngine)

        icon_service_engine._icon_pre_validator = Mock(spec=IconPreValidator)
        context.tx_batch = TransactionBatch()
        context.clear_batch = Mock()
        context.update_batch = Mock()

        from_ = Address.from_data(AddressPrefix.EOA, os.urandom(20))
        to_ = Address.from_data(AddressPrefix.CONTRACT, os.urandom(20))
        tx_index = randrange(0, 100)
        context.tx = Transaction(os.urandom(32), tx_index, from_, 0)
        context.msg = Message(from_)

        def intercept_charge_transaction_fee(*args, **kwargs):
            return {}, Mock(spec=int)

        IconServiceEngine._charge_transaction_fee.side_effect = \
            intercept_charge_transaction_fee

        icon_service_engine._icon_score_deploy_engine.attach_mock(
            Mock(return_value=False), 'is_data_type_supported')

        reason = Mock(spec=str)
        code = ExceptionCode.SCORE_ERROR
        mock_revert = Mock(side_effect=IconScoreException(reason))
        IconScoreEngine.invoke.side_effect = mock_revert

        raise_exception_start_tag("test_revert")
        tx_result = icon_service_engine._handle_icx_send_transaction(
            context, {
                'version': 3,
                'from': from_,
                'to': to_
            })
        raise_exception_end_tag("test_revert")
        assert tx_result.status == 0

        IconServiceEngine._charge_transaction_fee.assert_called()
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        assert trace.trace == TraceType.REVERT
        assert trace.data[0] == code
        assert trace.data[1] == reason
class TestTrace(unittest.TestCase):
    def setUp(self):
        db = Mock(spec=IconScoreDatabase)
        db.address = create_address(AddressPrefix.CONTRACT)
        context = IconScoreContext()
        traces = Mock(spec=list)

        context.tx = Mock(spec=Transaction)
        context.block = Mock(spec=Block)
        context.cumulative_step_used = Mock(spec=int)
        context.cumulative_step_used.attach_mock(Mock(), '__add__')
        context.step_counter = Mock(spec=IconScoreStepCounter)
        context.event_logs = Mock(spec=list)
        context.logs_bloom = Mock(spec=BloomFilter)
        context.traces = traces

        ContextContainer._push_context(context)
        context.icon_score_manager = Mock()
        context.icon_score_manager.get_owner = Mock(return_value=None)
        context.icon_score_manager.get_tx_hashes_by_score_address = \
            Mock(return_value=(create_tx_hash(), create_tx_hash()))
        context.internal_call = InternalCall(context)
        context.internal_call._other_score_call = Mock()
        context.internal_call.icx_engine = Mock(spec=IcxEngine)
        context.icon_score_mapper = Mock()
        context.icon_score_mapper.get_icon_score = Mock(
            return_value=TestScore(db))
        context.internal_call._validate_score_blacklist = Mock(
            return_value=False)
        self._score = TestScore(db)

    def tearDown(self):
        ContextContainer._clear_context()
        self._mock_icon_score = None

    def test_transfer(self):
        context = ContextContainer._get_context()
        context.type = IconScoreContextType.INVOKE
        to_ = create_address(AddressPrefix.EOA)
        context.internal_call.icx_engine = Mock(spec=IcxEngine)
        amount = 100
        self._score.icx.transfer(to_, amount)
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        self.assertEqual(TraceType.CALL, trace.trace)
        self.assertEqual(to_, trace.data[0])
        self.assertEqual(amount, trace.data[3])

    def test_send(self):
        context = ContextContainer._get_context()
        context.type = IconScoreContextType.INVOKE
        to_ = create_address(AddressPrefix.EOA)
        amount = 100
        self._score.icx.send(to_, amount)
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        self.assertEqual(TraceType.CALL, trace.trace)
        self.assertEqual(to_, trace.data[0])
        self.assertEqual(amount, trace.data[3])

    def test_call(self):
        context = ContextContainer._get_context()
        score_address = Mock(spec=Address)
        func_name = "testCall"
        to_ = Mock(spec=Address)
        amount = 100
        params = {'to': to_, 'amount': amount}

        self._score.call(score_address, func_name, params)
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        self.assertEqual(TraceType.CALL, trace.trace)
        self.assertEqual(score_address, trace.data[0])
        self.assertEqual(func_name, trace.data[1])
        self.assertEqual(params['to'], trace.data[2][0])
        self.assertEqual(params['amount'], trace.data[2][1])

    def test_interface_call(self):
        context = ContextContainer._get_context()
        score_address = Mock(spec=Address)
        to_ = Mock(spec=Address)
        amount = 100

        self._score.test_interface_call(score_address, to_, amount)
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        self.assertEqual(TraceType.CALL, trace.trace)
        self.assertEqual(score_address, trace.data[0])
        self.assertEqual('interfaceCall', trace.data[1])
        self.assertEqual(to_, trace.data[2][0])
        self.assertEqual(amount, trace.data[2][1])

    @patch('iconservice.icon_service_engine.IconServiceEngine.'
           '_charge_transaction_fee')
    def test_revert(self, IconServiceEngine_charge_transaction_fee):
        context = ContextContainer._get_context()

        self._icon_service_engine = IconServiceEngine()
        self._icon_service_engine._flag = 0
        self._icon_service_engine._icx_engine = Mock(spec=IcxEngine)
        self._icon_service_engine._icon_score_deploy_engine = \
            Mock(spec=IconScoreDeployEngine)

        self._icon_service_engine._icon_score_engine = Mock(
            spec=IconScoreEngine)
        self._icon_service_engine._icon_pre_validator = Mock(
            spec=IconPreValidator)
        context.tx_batch = TransactionBatch()

        from_ = Mock(spec=Address)
        to_ = Mock(spec=Address)

        def intercept_charge_transaction_fee(*args, **kwargs):
            return Mock(spec=int), Mock(spec=int)

        IconServiceEngine_charge_transaction_fee.side_effect = \
            intercept_charge_transaction_fee

        self._icon_service_engine._icon_score_deploy_engine.attach_mock(
            Mock(return_value=False), 'is_data_type_supported')

        reason = Mock(spec=str)
        code = ExceptionCode.SCORE_ERROR
        mock_revert = Mock(side_effect=RevertException(reason))
        self._icon_service_engine._icon_score_engine.attach_mock(
            mock_revert, "invoke")

        raise_exception_start_tag("test_revert")
        tx_result = self._icon_service_engine._handle_icx_send_transaction(
            context, {
                'version': 3,
                'from': from_,
                'to': to_
            })
        raise_exception_end_tag("test_revert")
        self.assertEqual(0, tx_result.status)

        IconServiceEngine_charge_transaction_fee.assert_called()
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        self.assertEqual(TraceType.REVERT, trace.trace)
        self.assertEqual(code, trace.data[0])
        self.assertEqual(reason, trace.data[1])

    @patch('iconservice.icon_service_engine.IconServiceEngine.'
           '_charge_transaction_fee')
    def test_throw(self, IconServiceEngine_charge_transaction_fee):
        context = ContextContainer._get_context()

        self._icon_service_engine = IconServiceEngine()
        self._icon_service_engine._flag = 0
        self._icon_service_engine._icx_engine = Mock(spec=IcxEngine)
        self._icon_service_engine._icon_score_deploy_engine = \
            Mock(spec=IconScoreDeployEngine)

        self._icon_service_engine._icon_score_engine = Mock(
            spec=IconScoreEngine)
        self._icon_service_engine._icon_pre_validator = Mock(
            spec=IconPreValidator)
        context.tx_batch = TransactionBatch()

        from_ = Mock(spec=Address)
        to_ = Mock(spec=Address)

        def intercept_charge_transaction_fee(*args, **kwargs):
            return Mock(spec=int), Mock(spec=int)

        IconServiceEngine_charge_transaction_fee.side_effect = \
            intercept_charge_transaction_fee

        self._icon_service_engine._icon_score_deploy_engine.attach_mock(
            Mock(return_value=False), 'is_data_type_supported')

        error = Mock(spec=str)
        code = ExceptionCode.SCORE_ERROR
        mock_exception = Mock(side_effect=IconScoreException(error, code))
        self._icon_service_engine._icon_score_engine.attach_mock(
            mock_exception, "invoke")

        raise_exception_start_tag("test_throw")
        tx_result = self._icon_service_engine._handle_icx_send_transaction(
            context, {
                'version': 3,
                'from': from_,
                'to': to_
            })
        raise_exception_end_tag("test_throw")
        self.assertEqual(0, tx_result.status)

        IconServiceEngine_charge_transaction_fee.assert_called()
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        self.assertEqual(TraceType.THROW, trace.trace)
        self.assertEqual(code, trace.data[0])
        self.assertEqual(error, trace.data[1])

    def test_to_dict_camel(self):
        context = ContextContainer._get_context()
        score_address = Mock(spec=Address)
        func_name = "testCall"
        to_ = Mock(spec=Address)
        amount = 100
        params = {'to': to_, 'amount': amount}

        self._score.call(score_address, func_name, params)
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        camel_dict = trace.to_dict(to_camel_case)
        self.assertIn('scoreAddress', camel_dict)
        self.assertIn('trace', camel_dict)
        self.assertIn('data', camel_dict)
        self.assertEqual(TraceType.CALL.name, camel_dict['trace'])
        self.assertEqual(4, len(camel_dict['data']))
Esempio n. 3
0
class TestTrace(unittest.TestCase):

    def setUp(self):
        db = Mock(spec=IconScoreDatabase)
        db.address = create_address(AddressPrefix.CONTRACT)
        context = IconScoreContext()
        context.icon_score_deploy_engine = Mock()
        traces = Mock(spec=list)

        context.tx = Mock(spec=Transaction)
        context.block = Mock(spec=Block)
        context.cumulative_step_used = Mock(spec=int)
        context.cumulative_step_used.attach_mock(Mock(), '__add__')
        context.step_counter = Mock(spec=IconScoreStepCounter)
        context.event_logs = []
        context.traces = traces
        context.tx_batch = TransactionBatch()

        ContextContainer._push_context(context)

        InternalCall._other_score_call = Mock()

        IconScoreContext.engine = ContextEngine(
            icx=Mock(spec=IcxEngine),
            deploy=Mock(spec=DeployEngine),
            fee=None,
            iiss=None,
            prep=None,
            issue=None
        )
        IconScoreContext.storage = ContextStorage(
            icx=None,
            deploy=Mock(spec=DeployStorage),
            fee=None,
            iiss=None,
            prep=None,
            issue=None,
            rc=None,
            meta=None
        )

        context.icon_score_mapper = Mock()
        context.icon_score_mapper.get_icon_score = Mock(return_value=TestScore(db))
        self._score = TestScore(db)

    def tearDown(self):
        InternalCall._other_score_call = OTHER_CALL
        ContextContainer._clear_context()
        self._mock_icon_score = None

    def test_transfer(self):
        context = ContextContainer._get_context()
        context.type = IconScoreContextType.INVOKE
        to_ = create_address(AddressPrefix.EOA)
        amount = 100
        self._score.icx.transfer(to_, amount)
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        self.assertEqual(TraceType.CALL, trace.trace)
        self.assertEqual(to_, trace.data[0])
        self.assertEqual(amount, trace.data[3])

    def test_send(self):
        context = ContextContainer._get_context()
        context.type = IconScoreContextType.INVOKE
        to_ = create_address(AddressPrefix.EOA)
        amount = 100
        self._score.icx.send(to_, amount)
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        self.assertEqual(TraceType.CALL, trace.trace)
        self.assertEqual(to_, trace.data[0])
        self.assertEqual(amount, trace.data[3])

    def test_call(self):
        context = ContextContainer._get_context()
        score_address = Mock(spec=Address)
        func_name = "testCall"
        to_ = Mock(spec=Address)
        amount = 100
        params = {'to': to_, 'amount': amount}

        self._score.call(score_address, func_name, params)
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        self.assertEqual(TraceType.CALL, trace.trace)
        self.assertEqual(score_address, trace.data[0])
        self.assertEqual(func_name, trace.data[1])
        self.assertEqual(params['to'], trace.data[2][0])
        self.assertEqual(params['amount'], trace.data[2][1])

    def test_interface_call(self):
        context = ContextContainer._get_context()
        score_address = Mock(spec=Address)
        to_ = Mock(spec=Address)
        amount = 100

        self._score.test_interface_call(score_address, to_, amount)
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        self.assertEqual(TraceType.CALL, trace.trace)
        self.assertEqual(score_address, trace.data[0])
        self.assertEqual('interfaceCall', trace.data[1])
        self.assertEqual(to_, trace.data[2][0])
        self.assertEqual(amount, trace.data[2][1])

    @patch('iconservice.icon_service_engine.IconServiceEngine.'
           '_charge_transaction_fee')
    @patch('iconservice.iconscore.icon_score_engine.IconScoreEngine.invoke')
    def test_revert(self, score_invoke, IconServiceEngine_charge_transaction_fee):
        context = ContextContainer._get_context()

        self._icon_service_engine = IconServiceEngine()
        self._icon_service_engine._icx_engine = Mock(spec=IcxEngine)
        self._icon_service_engine._icon_score_deploy_engine = \
            Mock(spec=DeployEngine)

        self._icon_service_engine._icon_pre_validator = Mock(
            spec=IconPreValidator)
        context.tx_batch = TransactionBatch()
        context.clear_batch = Mock()
        context.update_batch = Mock()

        from_ = Address.from_data(AddressPrefix.EOA, os.urandom(20))
        to_ = Address.from_data(AddressPrefix.CONTRACT, os.urandom(20))
        tx_index = randrange(0, 100)
        context.tx = Transaction(os.urandom(32), tx_index, from_, 0)
        context.msg = Message(from_)

        def intercept_charge_transaction_fee(*args, **kwargs):
            return {}, Mock(spec=int)

        IconServiceEngine_charge_transaction_fee.side_effect = \
            intercept_charge_transaction_fee

        self._icon_service_engine._icon_score_deploy_engine.attach_mock(
            Mock(return_value=False), 'is_data_type_supported')

        reason = Mock(spec=str)
        code = ExceptionCode.SCORE_ERROR
        mock_revert = Mock(side_effect=IconScoreException(reason))
        score_invoke.side_effect = mock_revert

        raise_exception_start_tag("test_revert")
        tx_result = self._icon_service_engine._handle_icx_send_transaction(
            context, {'version': 3, 'from': from_, 'to': to_})
        raise_exception_end_tag("test_revert")
        self.assertEqual(0, tx_result.status)

        IconServiceEngine_charge_transaction_fee.assert_called()
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        self.assertEqual(TraceType.REVERT, trace.trace)
        self.assertEqual(code, trace.data[0])
        self.assertEqual(reason, trace.data[1])

    @patch('iconservice.icon_service_engine.IconServiceEngine.'
           '_charge_transaction_fee')
    @patch('iconservice.iconscore.icon_score_engine.IconScoreEngine.invoke')
    def test_throw(self, score_invoke, IconServiceEngine_charge_transaction_fee):
        context = ContextContainer._get_context()

        self._icon_service_engine = IconServiceEngine()
        self._icon_service_engine._icx_engine = Mock(spec=IcxEngine)
        self._icon_service_engine._icon_score_deploy_engine = \
            Mock(spec=DeployEngine)

        self._icon_service_engine._icon_pre_validator = Mock(
            spec=IconPreValidator)
        context.tx_batch = TransactionBatch()
        context.clear_batch = Mock()
        context.update_batch = Mock()

        from_ = Address.from_data(AddressPrefix.EOA, os.urandom(20))
        to_ = Address.from_data(AddressPrefix.CONTRACT, os.urandom(20))
        tx_index = randrange(0, 100)
        context.tx = Transaction(os.urandom(32), tx_index, from_, 0)
        context.msg = Message(from_)

        def intercept_charge_transaction_fee(*args, **kwargs):
            return {}, Mock(spec=int)

        IconServiceEngine_charge_transaction_fee.side_effect = \
            intercept_charge_transaction_fee

        self._icon_service_engine._icon_score_deploy_engine.attach_mock(
            Mock(return_value=False), 'is_data_type_supported')

        error = Mock(spec=str)
        code = ExceptionCode.INVALID_PARAMETER
        mock_exception = Mock(side_effect=InvalidParamsException(error))
        score_invoke.side_effect = mock_exception

        raise_exception_start_tag("test_throw")
        tx_result = self._icon_service_engine._handle_icx_send_transaction(
            context, {'version': 3, 'from': from_, 'to': to_})
        raise_exception_end_tag("test_throw")
        self.assertEqual(0, tx_result.status)

        IconServiceEngine_charge_transaction_fee.assert_called()
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        self.assertEqual(TraceType.THROW, trace.trace)
        self.assertEqual(code, trace.data[0])
        self.assertEqual(error, trace.data[1])

    def test_to_dict_camel(self):
        context = ContextContainer._get_context()
        score_address = Mock(spec=Address)
        func_name = "testCall"
        to_ = Mock(spec=Address)
        amount = 100
        params = {'to': to_, 'amount': amount}

        self._score.call(score_address, func_name, params)
        context.traces.append.assert_called()
        trace = context.traces.append.call_args[0][0]
        camel_dict = trace.to_dict(to_camel_case)
        self.assertIn('scoreAddress', camel_dict)
        self.assertIn('trace', camel_dict)
        self.assertIn('data', camel_dict)
        self.assertEqual(TraceType.CALL.name, camel_dict['trace'])
        self.assertEqual(4, len(camel_dict['data']))