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
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_score_invoke_with_revert(self): table = {ConfigKey.SERVICE_FEE: True, ConfigKey.SERVICE_AUDIT: False, ConfigKey.SERVICE_DEPLOYER_WHITE_LIST: False, ConfigKey.SERVICE_SCORE_PACKAGE_VALIDATOR: False} # TODO: must apply the service flags to the engine # self._engine._flag = self._engine._make_service_flag(table) block_height = 1 block_hash = create_block_hash(b'block') block_timestamp = 0 tx_hash = create_tx_hash() value = 1 * 10 ** 18 self._to = create_address(AddressPrefix.CONTRACT) tx_v3 = { 'method': 'icx_sendTransaction', 'params': { 'version': 3, 'from': self._genesis_address, 'to': self._to, 'value': value, 'stepLimit': 20000, 'timestamp': 1234567890, 'txHash': tx_hash } } block = Block(block_height, block_hash, block_timestamp, self.genesis_block.hash, 0) context = _create_context(IconScoreContextType.QUERY) before_from_balance: int = \ IconScoreContext.engine.icx.get_balance(context, self.from_) self._engine._handle_score_invoke = \ Mock(return_value=None, side_effect=IconScoreException("force revert")) raise_exception_start_tag("test_score_invoke_with_revert") tx_results, state_root_hash, _, _ = self._engine.invoke(block, [tx_v3]) raise_exception_end_tag("test_score_invoke_with_revert") self.assertIsInstance(state_root_hash, bytes) self.assertEqual(len(state_root_hash), 32) self.assertEqual(len(tx_results), 1) tx_result: 'TransactionResult' = tx_results[0] self.assertIsNotNone(tx_result.failure) self.assertIsNone(tx_result.score_address) self.assertEqual(tx_result.status, 0) self.assertEqual(tx_result.block_height, block_height) self.assertEqual(tx_result.block_hash, block_hash) self.assertEqual(tx_result.tx_index, 0) self.assertEqual(tx_result.tx_hash, tx_hash) # step_used MUST BE 10**6 on protocol v2 step_unit = self._engine._step_counter_factory.get_step_cost( StepType.DEFAULT) self.assertEqual(tx_result.step_used, step_unit) step_price = self._engine._step_counter_factory.get_step_price() if IconScoreContextUtil._is_flag_on(IconScoreContext.icon_service_flag, IconServiceFlag.FEE): # step_price MUST BE 10**10 on protocol v2 self.assertEqual( step_price, self._engine._step_counter_factory.get_step_price()) else: self.assertEqual(step_price, 0) self.assertEqual(tx_result.step_price, step_price) self._engine.commit(block.height, block.hash, None) # Check whether fee charging works well context = _create_context(IconScoreContextType.QUERY) after_from_balance: int = \ IconScoreContext.engine.icx.get_balance(context, self.from_) fee = tx_result.step_price * tx_result.step_used self.assertEqual(after_from_balance, before_from_balance - fee)