diff --git a/iconservice/__init__.py b/iconservice/__init__.py index 94fa76a2d..921ef1a2a 100644 --- a/iconservice/__init__.py +++ b/iconservice/__init__.py @@ -31,8 +31,6 @@ create_address_with_key, create_interface_score ) -from .iconscore import icxunit - from .iconscore.icon_system_score_base import IconSystemScoreBase from .iconscore.system_score import InterfaceSystemScore from .__version__ import __version__ diff --git a/iconservice/__version__.py b/iconservice/__version__.py index 48c2f6b0b..8adfee4fe 100644 --- a/iconservice/__version__.py +++ b/iconservice/__version__.py @@ -1 +1 @@ -__version__ = '1.7.1' +__version__ = '1.7.2' diff --git a/iconservice/icon_service_engine.py b/iconservice/icon_service_engine.py index ba810bae0..630a58f31 100644 --- a/iconservice/icon_service_engine.py +++ b/iconservice/icon_service_engine.py @@ -753,7 +753,7 @@ def _update_productivity(cls, for address, vote_state in validators: dirty_prep: Optional['PRep'] = context.get_prep(address, mutable=True) - assert isinstance(dirty_prep, PRep) + assert isinstance(dirty_prep, PRep), f"dirty_prep: {address}" is_validator: bool = vote_state != BlockVoteStatus.NONE.value @@ -776,7 +776,7 @@ def _update_last_generate_block_height(cls, return dirty_prep: 'PRep' = context.get_prep(prev_block_generator, mutable=True) - assert isinstance(dirty_prep, PRep) + assert isinstance(dirty_prep, PRep), f"dirty_prep: {address}" dirty_prep.last_generate_block_height = context.block.height - 1 context.put_dirty_prep(dirty_prep) diff --git a/iconservice/iconscore/icon_score_base.py b/iconservice/iconscore/icon_score_base.py index bd9520f3e..293ebbcc1 100644 --- a/iconservice/iconscore/icon_score_base.py +++ b/iconservice/iconscore/icon_score_base.py @@ -20,7 +20,6 @@ from inspect import isfunction, signature, Parameter from typing import TYPE_CHECKING, Callable, Any, List, Tuple, Mapping -from . import icxunit from .context.context import ContextGetter, ContextContainer from .icon_score_base2 import InterfaceScore, revert, Block from .icon_score_constant import ( @@ -64,15 +63,13 @@ INDEXED_ARGS_LIMIT = 3 -def interface(func=None, *, payable=False): +def interface(func): """ A decorator for the functions of InterfaceScore. If other SCORE has the function whose signature is the same as defined with @interface decorator, the function can be invoked via InterfaceScore class instance """ - if func is None: - return partial(interface, payable=payable) cls_name, func_name = str(func.__qualname__).split('.') if not isfunction(func): @@ -83,27 +80,6 @@ def interface(func=None, *, payable=False): set_score_flag_on(func, ScoreFlag.INTERFACE) - sig = signature(func) - params = sig.parameters - - it = reversed(params.items()) - if payable: - try: - var_name, var_type = next(it) - if var_type.annotation is not icxunit.Loop: - raise StopIteration - - default_value = var_type.default - if not (default_value is Parameter.empty or - isinstance(default_value, icxunit.Loop)): - raise IllegalFormatException(f"Default value should be icxunit.Loop: {str(func.__qualname__)}") - except StopIteration: - raise IllegalFormatException(f"Last argument should be icxunit.Loop: {str(func.__qualname__)}") - - for _, var_type in it: - if var_type.annotation is icxunit.Loop: - raise IllegalFormatException(f"icxunit.Loop is not allowed: {str(func.__qualname__)}") - @wraps(func) def __wrapper(calling_obj: "InterfaceScore", *args, **kwargs): if not isinstance(calling_obj, InterfaceScore): @@ -114,25 +90,8 @@ def __wrapper(calling_obj: "InterfaceScore", *args, **kwargs): addr_to = calling_obj.addr_to addr_from: 'Address' = context.current_address - if payable: - unit: Optional['icxunit.Loop'] = kwargs.get(var_name) - if unit: - amount = int(unit) - del kwargs[var_name] - else: - if args: - unit: 'icxunit.Loop' = args[-1] - if isinstance(unit, icxunit.Loop): - amount = int(unit) - args = tuple(args[:-1]) - else: - raise InvalidParamsException(f"{type(unit)} is not icxunit.Loop") - else: - if default_value is Parameter.empty: - raise InvalidParamsException(f"{var_name} is not found") - amount = int(default_value) - else: - amount = 0 + amount: int = getattr(calling_obj, "_InterfaceScore__get_icx")() + getattr(calling_obj, "_InterfaceScore__reset_icx")() if addr_to is None: raise InvalidInterfaceException('Cannot create an interface SCORE with a None address') diff --git a/iconservice/iconscore/icon_score_base2.py b/iconservice/iconscore/icon_score_base2.py index fb5817aa4..a1fd262cb 100644 --- a/iconservice/iconscore/icon_score_base2.py +++ b/iconservice/iconscore/icon_score_base2.py @@ -53,6 +53,7 @@ def __init__(self, addr_to: 'Address'): A Python init function. Invoked when the contract call create_interface_score() """ self.__addr_to = addr_to + self.__icx = 0 @property def addr_to(self) -> 'Address': @@ -63,6 +64,19 @@ def addr_to(self) -> 'Address': """ return self.__addr_to + def icx(self, value: int): + if not (isinstance(value, int) and value >= 0): + raise InvalidParamsException(f"Invalid icx: {value}") + + self.__icx = value + return self + + def __get_icx(self) -> int: + return self.__icx + + def __reset_icx(self): + self.__icx = 0 + class Block(object): def __init__(self, block_height: int, timestamp: int) -> None: @@ -377,4 +391,3 @@ def create_interface_score(addr_to: 'Address', if interface_cls is InterfaceScore: raise InvalidInstanceException(FORMAT_IS_NOT_DERIVED_OF_OBJECT.format(InterfaceScore.__name__)) return interface_cls(addr_to) - diff --git a/iconservice/iconscore/icon_score_context.py b/iconservice/iconscore/icon_score_context.py index a3493c779..47d220a9a 100644 --- a/iconservice/iconscore/icon_score_context.py +++ b/iconservice/iconscore/icon_score_context.py @@ -242,7 +242,8 @@ def _update_prep_address_converter(self, dirty_prep: 'PRep'): prev_node=old_prep.node_address) elif dirty_prep.status != PRepStatus.ACTIVE: # unregisterPRep or disqualified by productivity penalty - self._prep_address_converter.delete_node_address(node=dirty_prep.node_address) + self._prep_address_converter.delete_node_address(node=dirty_prep.node_address, + prep=dirty_prep.address) def _update_term(self, dirty_prep: 'PRep'): """Update term info with dirty_prep diff --git a/iconservice/iconscore/icxunit.py b/iconservice/iconscore/icxunit.py deleted file mode 100644 index 2110652cc..000000000 --- a/iconservice/iconscore/icxunit.py +++ /dev/null @@ -1,3 +0,0 @@ - -class Loop(int): - pass diff --git a/iconservice/prep/penalty_imposer.py b/iconservice/prep/penalty_imposer.py index b2224e0fa..cd2e85dd8 100644 --- a/iconservice/prep/penalty_imposer.py +++ b/iconservice/prep/penalty_imposer.py @@ -54,11 +54,15 @@ def run(self, if self._check_block_validation_penalty(prep): Logger.info(f"PenaltyImposer statistics({PenaltyReason.BLOCK_VALIDATION}): " + f"prep: {prep.address} " + f"node_address: {prep.node_address} " f"prep_total_blocks: {prep.total_blocks} " f"prep_block_validation_proportion: {prep.block_validation_proportion}") reason = PenaltyReason.BLOCK_VALIDATION if self._check_low_productivity_penalty(prep): Logger.info(f"PenaltyImposer statistics({PenaltyReason.LOW_PRODUCTIVITY}): " + f"prep: {prep.address} " + f"node_address: {prep.node_address} " f"prep_total_blocks: {prep.total_blocks} " f"prep_unvalidated_sequence_blocks: {prep.unvalidated_sequence_blocks}") reason = PenaltyReason.LOW_PRODUCTIVITY diff --git a/iconservice/prep/prep_address_converter.py b/iconservice/prep/prep_address_converter.py index 98933341e..156732b13 100644 --- a/iconservice/prep/prep_address_converter.py +++ b/iconservice/prep/prep_address_converter.py @@ -71,7 +71,11 @@ def add_node_address(self, node: 'Address', prep: 'Address'): raise InvalidParamsException(f"nodeAddress already in use: {node}") self._node_address_mapper[node] = prep - def delete_node_address(self, node: 'Address'): + def delete_node_address(self, node: 'Address', prep: 'Address'): + self._add_prev_node_address(node=node, prep=prep) + self._delete_node_address(node) + + def _delete_node_address(self, node: 'Address'): if node in self._node_address_mapper: del self._node_address_mapper[node] @@ -81,7 +85,7 @@ def _add_prev_node_address(self, node: 'Address', prep: 'Address'): def replace_node_address(self, node: 'Address', prep: 'Address', prev_node: 'Address'): self._add_prev_node_address(node=prev_node, prep=prep) - self.delete_node_address(node=prev_node) + self._delete_node_address(node=prev_node) self.add_node_address(node=node, prep=prep) def copy(self) -> 'PRepAddressConverter': @@ -99,6 +103,7 @@ def validate_node_address(self, def get_prep_address_from_node_address(self, node_address: 'Address') -> 'Address': - - return self._prev_node_address_mapper.get(node_address, - self._node_address_mapper.get(node_address, node_address)) + ret: 'Address' = self._node_address_mapper.get(node_address) + if ret is None: + ret = self._prev_node_address_mapper.get(node_address, node_address) + return ret diff --git a/tests/integrate_test/iiss/decentralized/test_preps_divide_node_address.py b/tests/integrate_test/iiss/decentralized/test_preps_divide_node_address.py index 181ce57be..239da14ef 100644 --- a/tests/integrate_test/iiss/decentralized/test_preps_divide_node_address.py +++ b/tests/integrate_test/iiss/decentralized/test_preps_divide_node_address.py @@ -150,10 +150,10 @@ def test_prep_set_node_address_check_generator(self): prev_block_generator = self._accounts[0].address prev_block_votes = [(x.address, True) for x in self._accounts[1:PREP_MAIN_PREPS]] block, tx_results, _, _, next_preps = self.debug_make_and_req_block(tx_list=[], - prev_block_generator=prev_block_generator, - prev_block_validators=None, - prev_block_votes=prev_block_votes, - block=None) + prev_block_generator=prev_block_generator, + prev_block_validators=None, + prev_block_votes=prev_block_votes, + block=None) self.assertEqual(tx_results[0].status, True) self.assertEqual(next_preps, None) @@ -169,10 +169,10 @@ def test_prep_set_node_address_check_generator(self): prev_block_votes = [(x.address, True) for x in self._accounts[1:PREP_MAIN_PREPS]] block, tx_results, _, _, next_preps = self.debug_make_and_req_block(tx_list=[tx], - prev_block_generator=prev_block_generator, - prev_block_validators=None, - prev_block_votes=prev_block_votes, - block=None) + prev_block_generator=prev_block_generator, + prev_block_validators=None, + prev_block_votes=prev_block_votes, + block=None) self.assertEqual(tx_results[0].status, True) self.assertEqual(next_preps["preps"][0]["id"], dummy_node2) self._write_precommit_state(block) @@ -207,10 +207,10 @@ def test_prep_set_node_address_check_votes(self): prev_block_generator = self._accounts[0].address prev_block_votes = [(x.address, True) for x in self._accounts[1:PREP_MAIN_PREPS]] block, tx_results, _, _, next_preps = self.debug_make_and_req_block(tx_list=[], - prev_block_generator=prev_block_generator, - prev_block_validators=None, - prev_block_votes=prev_block_votes, - block=None) + prev_block_generator=prev_block_generator, + prev_block_validators=None, + prev_block_votes=prev_block_votes, + block=None) self.assertEqual(tx_results[0].status, True) self.assertEqual(next_preps, None) @@ -226,10 +226,10 @@ def test_prep_set_node_address_check_votes(self): prev_block_votes = [(x.address, True) for x in self._accounts[1:PREP_MAIN_PREPS]] block, tx_results, _, _, next_preps = self.debug_make_and_req_block(tx_list=[tx], - prev_block_generator=prev_block_generator, - prev_block_validators=None, - prev_block_votes=prev_block_votes, - block=None) + prev_block_generator=prev_block_generator, + prev_block_validators=None, + prev_block_votes=prev_block_votes, + block=None) self.assertEqual(tx_results[0].status, True) self.assertEqual(next_preps["preps"][1]["id"], dummy_node2) self._write_precommit_state(block) @@ -474,3 +474,107 @@ def test_scenario6(self): # After calling write_precommit_state() ret: Dict[str, Union[str, int, bytes, 'Address']] = self.get_prep(prep_a) assert ret["nodeAddress"] == prep_a.address + + def test_change_node_prep1(self): + # 1 block + # PRepA a ---- z + # penalty PRepA (low productivity) + + self.set_revision(Revision.DIVIDE_NODE_ADDRESS.value) + + self.distribute_icx(accounts=self._accounts[:PREP_MAIN_PREPS], + init_balance=1 * ICX_IN_LOOP) + + # PRepA: 0 + # PRepB: 1 + prep_a: 'EOAAccount' = self._accounts[0] + node_address: 'Address' = create_address() + + tx_list: list = [ + self.create_set_prep_tx( + from_=prep_a, + set_data={ + "nodeAddress": str(node_address) + } + ) + ] + + self.process_confirm_block_tx( + tx_list, + prev_block_generator=None, + prev_block_validators=None + ) + + PREV_PENALTY_GRACE_PERIOD = IconScoreContext.engine.prep._penalty_imposer._penalty_grace_period + PREV_LOW_PRODUCTIVITY_PENALTY_THRESHOLD = \ + IconScoreContext.engine.prep._penalty_imposer._low_productivity_penalty_threshold + + PENALTY_GRACE_PERIOD = 0 + # enable low productivity + LOW_PRODUCTIVITY_PENALTY_THRESHOLD = 1 + + IconScoreContext.engine.prep._penalty_imposer._penalty_grace_period = PENALTY_GRACE_PERIOD + IconScoreContext.engine.prep._penalty_imposer._low_productivity_penalty_threshold = \ + LOW_PRODUCTIVITY_PENALTY_THRESHOLD + + votes = [[node_address, False]] + \ + [[account.address, True] for account in self._accounts[2:PREP_MAIN_PREPS]] + tx_results = self.make_blocks(to=self._block_height + 2, + prev_block_generator=self._accounts[1].address, + prev_block_votes=votes) + + # assert Error! + with self.assertRaises(AssertionError) as e: + self.make_blocks( + to=self._block_height + 1, + prev_block_generator=self._accounts[1].address, + prev_block_votes=votes) + + self.assertEqual(e.exception.args[0], f"dirty_prep: {node_address}") + + IconScoreContext.engine.prep._penalty_imposer._penalty_grace_period = PREV_PENALTY_GRACE_PERIOD + IconScoreContext.engine.prep._penalty_imposer._low_productivity_penalty_threshold = \ + PREV_LOW_PRODUCTIVITY_PENALTY_THRESHOLD + + def test_change_node_prep2(self): + # 1 block + # PRepA a ---- z + # unreg PRepA + + self.set_revision(Revision.DIVIDE_NODE_ADDRESS.value) + + self.distribute_icx(accounts=self._accounts[:PREP_MAIN_PREPS], + init_balance=1 * ICX_IN_LOOP) + + # PRepA: 0 + # PRepB: 1 + prep_a: 'EOAAccount' = self._accounts[0] + node_address: 'Address' = create_address() + + tx_list: list = [ + self.create_set_prep_tx( + from_=prep_a, + set_data={ + "nodeAddress": str(node_address) + } + ) + ] + + self.process_confirm_block_tx(tx_list) + + self.unregister_prep(prep_a) + + votes = [[node_address, False]] + \ + [[account.address, True] for account in self._accounts[2:PREP_MAIN_PREPS]] + tx_results = self.make_blocks(to=self._block_height + 1, + prev_block_generator=self._accounts[1].address, + prev_block_votes=votes) + + # assert Error! + with self.assertRaises(AssertionError) as e: + self.make_blocks( + to=self._block_height + 1, + prev_block_generator=self._accounts[1].address, + prev_block_votes=votes) + + self.assertEqual(e.exception.args[0], f"dirty_prep: {node_address}") diff --git a/tests/integrate_test/samples/icx_method_chaining/callee_score/package.json b/tests/integrate_test/samples/icx_method_chaining/callee_score/package.json new file mode 100644 index 000000000..e41448d4d --- /dev/null +++ b/tests/integrate_test/samples/icx_method_chaining/callee_score/package.json @@ -0,0 +1,5 @@ +{ + "version": "0.0.1", + "main_module": "score", + "main_score": "Score" +} \ No newline at end of file diff --git a/tests/integrate_test/samples/icx_method_chaining/callee_score/score.py b/tests/integrate_test/samples/icx_method_chaining/callee_score/score.py new file mode 100644 index 000000000..11d38829d --- /dev/null +++ b/tests/integrate_test/samples/icx_method_chaining/callee_score/score.py @@ -0,0 +1,85 @@ +from iconservice import * + + +class Score(IconScoreBase): + + def __init__(self, db: IconScoreDatabase) -> None: + super().__init__(db) + self._bool = VarDB("bool", db, bool) + self._bytes = VarDB("bytes", db, bytes) + self._int = VarDB("int", db, int) + self._str = VarDB("str", db, str) + self._address = VarDB("Address", db, Address) + + def on_install(self, value: int=0) -> None: + super().on_install() + self.__init() + + def on_update(self) -> None: + super().on_update() + self.__init() + + def __init(self): + self._bool.set(False) + self._bytes.set(b"") + self._int.set(0) + self._str.set("") + self._address.set(Address.from_prefix_and_int(AddressPrefix.EOA, 0)) + + @payable + @external + def setBool(self, value: bool): + self._bool.set(value) + + @external(readonly=True) + def getBool(self) -> bool: + return self._bool.get() + + @payable + @external + def setBytes(self, value: bytes): + self._bytes.set(value) + + @external(readonly=True) + def getBytes(self) -> bytes: + return self._bytes.get() + + @payable + @external + def setInt(self, value: int): + self._int.set(value) + + @external + def getInt(self) -> int: + return self._int.get() + + @payable + @external + def setStr(self, value: str): + self._str.set(value) + + @external(readonly=True) + def getStr(self) -> str: + return self._str.get() + + @payable + @external + def setAddress(self, value: Address): + self._address.set(value) + + @external(readonly=True) + def getAddress(self) -> Address: + return self._address.get() + + @payable + @external + def func_payable(self): + pass + + @external + def func_non_payable(self): + pass + + @payable + def fallback(self) -> None: + pass diff --git a/tests/integrate_test/samples/icx_method_chaining/caller_score/package.json b/tests/integrate_test/samples/icx_method_chaining/caller_score/package.json new file mode 100644 index 000000000..e41448d4d --- /dev/null +++ b/tests/integrate_test/samples/icx_method_chaining/caller_score/package.json @@ -0,0 +1,5 @@ +{ + "version": "0.0.1", + "main_module": "score", + "main_score": "Score" +} \ No newline at end of file diff --git a/tests/integrate_test/samples/icx_method_chaining/caller_score/score.py b/tests/integrate_test/samples/icx_method_chaining/caller_score/score.py new file mode 100644 index 000000000..a5bddda72 --- /dev/null +++ b/tests/integrate_test/samples/icx_method_chaining/caller_score/score.py @@ -0,0 +1,102 @@ +from iconservice import * + + +class CalleeInterface(InterfaceScore): + @interface + def setBool(self, value: bool): pass + + @interface + def setBytes(self, value: bool): pass + + @interface + def setInt(self, value: int): pass + + @interface + def setStr(self, value: str): pass + + @interface + def setAddress(self, value: Address): pass + + @interface + def func_payable(self): pass + + @interface + def func_non_payable(self): pass + + +class Score(IconScoreBase): + + def __init__(self, db: IconScoreDatabase) -> None: + super().__init__(db) + self._address = VarDB("address", db, value_type=Address) + + def on_install(self) -> None: + super().on_install() + + def on_update(self) -> None: + super().on_update() + + @external + def setCallee(self, address: Address): + self._address.set(address) + + @payable + @external + def setBool(self, value: bool): + callee = self._get_callee() + callee.icx(self.msg.value).setBool(value) + + @payable + @external + def setBytes(self, value: bytes): + callee = self._get_callee() + callee.icx(self.msg.value).setBytes(value) + + @payable + @external + def setInt(self, value: int): + callee = self._get_callee() + callee.icx(self.msg.value).setInt(value) + + @payable + @external + def setStr(self, value: str): + callee = self._get_callee() + callee.icx(self.msg.value).setStr(value) + + @payable + @external + def setAddress(self, value: Address): + callee = self._get_callee() + callee.icx(self.msg.value).setAddress(value) + + @payable + @external + def func_with_payable_internal_call(self): + self._call_method_of_callee(self.msg.value) + + def _call_method_of_callee(self, value: int): + callee = self._get_callee() + callee.icx(value).func_payable() + callee.func_payable() + callee.icx(0).func_payable() + + @payable + @external + def func_with_non_payable_internal_call(self): + callee = self._get_callee() + callee.icx(self.msg.value).func_non_payable() + + @external + def non_payable_func_with_icx_internal_call(self, value: int): + callee = self._get_callee() + callee.icx(value).func_payable() + + def _get_callee(self) -> CalleeInterface: + address = self._address.get() + return self.create_interface_score(address, CalleeInterface) + + @payable + def fallback(self) -> None: + callee = self._get_callee() + callee.icx(self.msg.value // 2).func_payable() diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score1/package.json b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score1/package.json deleted file mode 100644 index 3ec13cbff..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score1/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "0.0.1", - "main_file": "sample_link_score", - "main_score": "SampleLinkScore" -} \ No newline at end of file diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score1/sample_link_score.py b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score1/sample_link_score.py deleted file mode 100644 index a2c69990e..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score1/sample_link_score.py +++ /dev/null @@ -1,30 +0,0 @@ -from iconservice import * - - -class SampleInterface(InterfaceScore): - @interface(payable=True) - def func(self, amount: icxunit.Loop, invalid_value: int): pass - - -class SampleLinkScore(IconScoreBase): - _SCORE_ADDR = 'score_addr' - - def __init__(self, db: IconScoreDatabase) -> None: - super().__init__(db) - self._value = VarDB('value', db, value_type=int) - self._addr_score = VarDB(self._SCORE_ADDR, db, value_type=Address) - - def on_install(self, value: int=0) -> None: - super().on_install() - self._value.set(value) - - def on_update(self) -> None: - super().on_update() - - @external - def add_score_func(self, score_addr: Address): - self._addr_score.set(score_addr) - - @payable - def fallback(self) -> None: - pass diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score2/package.json b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score2/package.json deleted file mode 100644 index 3ec13cbff..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score2/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "0.0.1", - "main_file": "sample_link_score", - "main_score": "SampleLinkScore" -} \ No newline at end of file diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score2/sample_link_score.py b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score2/sample_link_score.py deleted file mode 100644 index 72dc7acb6..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score2/sample_link_score.py +++ /dev/null @@ -1,30 +0,0 @@ -from iconservice import * - - -class SampleInterface(InterfaceScore): - @interface - def func(self, amount: icxunit.Loop): pass - - -class SampleLinkScore(IconScoreBase): - _SCORE_ADDR = 'score_addr' - - def __init__(self, db: IconScoreDatabase) -> None: - super().__init__(db) - self._value = VarDB('value', db, value_type=int) - self._addr_score = VarDB(self._SCORE_ADDR, db, value_type=Address) - - def on_install(self, value: int=0) -> None: - super().on_install() - self._value.set(value) - - def on_update(self) -> None: - super().on_update() - - @external - def add_score_func(self, score_addr: Address): - self._addr_score.set(score_addr) - - @payable - def fallback(self) -> None: - pass diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score3/package.json b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score3/package.json deleted file mode 100644 index 3ec13cbff..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score3/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "0.0.1", - "main_file": "sample_link_score", - "main_score": "SampleLinkScore" -} \ No newline at end of file diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score3/sample_link_score.py b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score3/sample_link_score.py deleted file mode 100644 index 064372364..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score3/sample_link_score.py +++ /dev/null @@ -1,30 +0,0 @@ -from iconservice import * - - -class SampleInterface(InterfaceScore): - @interface(payable=True) - def func(self, value1: icxunit.Loop, value2: icxunit.Loop): pass - - -class SampleLinkScore(IconScoreBase): - _SCORE_ADDR = 'score_addr' - - def __init__(self, db: IconScoreDatabase) -> None: - super().__init__(db) - self._value = VarDB('value', db, value_type=int) - self._addr_score = VarDB(self._SCORE_ADDR, db, value_type=Address) - - def on_install(self, value: int=0) -> None: - super().on_install() - self._value.set(value) - - def on_update(self) -> None: - super().on_update() - - @external - def add_score_func(self, score_addr: Address): - self._addr_score.set(score_addr) - - @payable - def fallback(self) -> None: - pass diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score4/package.json b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score4/package.json deleted file mode 100644 index 3ec13cbff..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score4/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "0.0.1", - "main_file": "sample_link_score", - "main_score": "SampleLinkScore" -} \ No newline at end of file diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score4/sample_link_score.py b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score4/sample_link_score.py deleted file mode 100644 index d4c5dd3a8..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score4/sample_link_score.py +++ /dev/null @@ -1,30 +0,0 @@ -from iconservice import * - - -class SampleInterface(InterfaceScore): - @interface - def func(self, value1: icxunit.Loop, value2: icxunit.Loop): pass - - -class SampleLinkScore(IconScoreBase): - _SCORE_ADDR = 'score_addr' - - def __init__(self, db: IconScoreDatabase) -> None: - super().__init__(db) - self._value = VarDB('value', db, value_type=int) - self._addr_score = VarDB(self._SCORE_ADDR, db, value_type=Address) - - def on_install(self, value: int=0) -> None: - super().on_install() - self._value.set(value) - - def on_update(self) -> None: - super().on_update() - - @external - def add_score_func(self, score_addr: Address): - self._addr_score.set(score_addr) - - @payable - def fallback(self) -> None: - pass diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score5/package.json b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score5/package.json deleted file mode 100644 index 3ec13cbff..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score5/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "0.0.1", - "main_file": "sample_link_score", - "main_score": "SampleLinkScore" -} \ No newline at end of file diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score5/sample_link_score.py b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score5/sample_link_score.py deleted file mode 100644 index 674cd82ff..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score5/sample_link_score.py +++ /dev/null @@ -1,30 +0,0 @@ -from iconservice import * - - -class SampleInterface(InterfaceScore): - @interface - def func(self, value1: icxunit.Loop): pass - - -class SampleLinkScore(IconScoreBase): - _SCORE_ADDR = 'score_addr' - - def __init__(self, db: IconScoreDatabase) -> None: - super().__init__(db) - self._value = VarDB('value', db, value_type=int) - self._addr_score = VarDB(self._SCORE_ADDR, db, value_type=Address) - - def on_install(self, value: int=0) -> None: - super().on_install() - self._value.set(value) - - def on_update(self) -> None: - super().on_update() - - @external - def add_score_func(self, score_addr: Address): - self._addr_score.set(score_addr) - - @payable - def fallback(self) -> None: - pass diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score6/package.json b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score6/package.json deleted file mode 100644 index 3ec13cbff..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score6/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "0.0.1", - "main_file": "sample_link_score", - "main_score": "SampleLinkScore" -} \ No newline at end of file diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score6/sample_link_score.py b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score6/sample_link_score.py deleted file mode 100644 index 8305265c2..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score6/sample_link_score.py +++ /dev/null @@ -1,31 +0,0 @@ -from iconservice import * - - -class SampleInterface(InterfaceScore): - @classmethod - @interface - def func(cls, value1: icxunit.Loop): pass - - -class SampleLinkScore(IconScoreBase): - _SCORE_ADDR = 'score_addr' - - def __init__(self, db: IconScoreDatabase) -> None: - super().__init__(db) - self._value = VarDB('value', db, value_type=int) - self._addr_score = VarDB(self._SCORE_ADDR, db, value_type=Address) - - def on_install(self, value: int=0) -> None: - super().on_install() - self._value.set(value) - - def on_update(self) -> None: - super().on_update() - - @external - def add_score_func(self, score_addr: Address): - self._addr_score.set(score_addr) - - @payable - def fallback(self) -> None: - pass diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score7/package.json b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score7/package.json deleted file mode 100644 index 3ec13cbff..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score7/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "0.0.1", - "main_file": "sample_link_score", - "main_score": "SampleLinkScore" -} \ No newline at end of file diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score7/sample_link_score.py b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score7/sample_link_score.py deleted file mode 100644 index 9e33126ac..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score7/sample_link_score.py +++ /dev/null @@ -1,31 +0,0 @@ -from iconservice import * - - -class SampleInterface(InterfaceScore): - @staticmethod - @interface - def func(value1: icxunit.Loop): pass - - -class SampleLinkScore(IconScoreBase): - _SCORE_ADDR = 'score_addr' - - def __init__(self, db: IconScoreDatabase) -> None: - super().__init__(db) - self._value = VarDB('value', db, value_type=int) - self._addr_score = VarDB(self._SCORE_ADDR, db, value_type=Address) - - def on_install(self, value: int=0) -> None: - super().on_install() - self._value.set(value) - - def on_update(self) -> None: - super().on_update() - - @external - def add_score_func(self, score_addr: Address): - self._addr_score.set(score_addr) - - @payable - def fallback(self) -> None: - pass diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score8/package.json b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score8/package.json deleted file mode 100644 index 3ec13cbff..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score8/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "0.0.1", - "main_file": "sample_link_score", - "main_score": "SampleLinkScore" -} \ No newline at end of file diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score8/sample_link_score.py b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score8/sample_link_score.py deleted file mode 100644 index bf3387ffe..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_link_score8/sample_link_score.py +++ /dev/null @@ -1,30 +0,0 @@ -from iconservice import * - - -class SampleInterface(InterfaceScore): - @interface(payable=True) - def func_no_params_with_icx_invalid_default(self, amount: icxunit.Loop = 0): pass - - -class SampleLinkScore(IconScoreBase): - _SCORE_ADDR = 'score_addr' - - def __init__(self, db: IconScoreDatabase) -> None: - super().__init__(db) - self._value = VarDB('value', db, value_type=int) - self._addr_score = VarDB(self._SCORE_ADDR, db, value_type=Address) - - def on_install(self, value: int=0) -> None: - super().on_install() - self._value.set(value) - - def on_update(self) -> None: - super().on_update() - - @external - def add_score_func(self, score_addr: Address): - self._addr_score.set(score_addr) - - @payable - def fallback(self) -> None: - pass diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_score/package.json b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_score/package.json deleted file mode 100644 index 2369760f8..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_score/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "0.0.1", - "main_file": "sample_score", - "main_score": "SampleScore" -} \ No newline at end of file diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_score/sample_score.py b/tests/integrate_test/samples/invalid_interface_score/sample_invalid_score/sample_score.py deleted file mode 100644 index b6c446c17..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_invalid_score/sample_score.py +++ /dev/null @@ -1,19 +0,0 @@ -from iconservice import * - - -class SampleScore(IconScoreBase): - def __init__(self, db: IconScoreDatabase) -> None: - super().__init__(db) - self._value = VarDB('value', db, value_type=int) - - def on_install(self, value: int=0) -> None: - super().on_install() - self._value.set(value) - - def on_update(self) -> None: - super().on_update() - - @external - @payable - def func_params_icxunit_loop_with_icx(self, value: icxunit.Loop): - pass diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_link_score/package.json b/tests/integrate_test/samples/invalid_interface_score/sample_link_score/package.json deleted file mode 100644 index 3ec13cbff..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_link_score/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "0.0.1", - "main_file": "sample_link_score", - "main_score": "SampleLinkScore" -} \ No newline at end of file diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_link_score/sample_link_score.py b/tests/integrate_test/samples/invalid_interface_score/sample_link_score/sample_link_score.py deleted file mode 100644 index 08baaea26..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_link_score/sample_link_score.py +++ /dev/null @@ -1,59 +0,0 @@ -from iconservice import * - - -class SampleInterface(InterfaceScore): - @interface(payable=True) - def func_params_int_with_icx(self, value: int, amount: icxunit.Loop): pass - - @interface(payable=True) - def func_params_str_with_icx(self, value: str, amount: icxunit.Loop): pass - - @interface(payable=True) - def func_no_params_with_icx(self, amount: icxunit.Loop): pass - - @interface(payable=True) - def func_no_params_with_icx_default(self, amount: icxunit.Loop = icxunit.Loop(2 * 10**18)): pass - - -class SampleLinkScore(IconScoreBase): - _SCORE_ADDR = 'score_addr' - - def __init__(self, db: IconScoreDatabase) -> None: - super().__init__(db) - self._value = VarDB('value', db, value_type=int) - self._addr_score = VarDB(self._SCORE_ADDR, db, value_type=Address) - - def on_install(self, value: int=0) -> None: - super().on_install() - self._value.set(value) - - def on_update(self) -> None: - super().on_update() - - @external - def add_score_func(self, score_addr: Address): - self._addr_score.set(score_addr) - - @external - def test_func_params_int_with_icx(self, value: int, amount: int): - test_interface = self.create_interface_score(self._addr_score.get(), SampleInterface) - test_interface.func_params_int_with_icx(value=value, amount=icxunit.Loop(amount)) - - @external - def test_func_params_int_with_icx(self, value: str, amount: int): - test_interface = self.create_interface_score(self._addr_score.get(), SampleInterface) - test_interface.func_params_str_with_icx(value=value, amount=icxunit.Loop(amount)) - - @external - def test_func_no_params_with_icx(self, amount: int): - test_interface = self.create_interface_score(self._addr_score.get(), SampleInterface) - test_interface.func_no_params_with_icx(amount=icxunit.Loop(amount)) - - @external - def test_func_no_params_with_icx_default(self): - test_interface = self.create_interface_score(self._addr_score.get(), SampleInterface) - test_interface.func_no_params_with_icx_default() - - @payable - def fallback(self) -> None: - pass diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_score/package.json b/tests/integrate_test/samples/invalid_interface_score/sample_score/package.json deleted file mode 100644 index 2369760f8..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_score/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "0.0.1", - "main_file": "sample_score", - "main_score": "SampleScore" -} \ No newline at end of file diff --git a/tests/integrate_test/samples/invalid_interface_score/sample_score/sample_score.py b/tests/integrate_test/samples/invalid_interface_score/sample_score/sample_score.py deleted file mode 100644 index 2e40d56a6..000000000 --- a/tests/integrate_test/samples/invalid_interface_score/sample_score/sample_score.py +++ /dev/null @@ -1,34 +0,0 @@ -from iconservice import * - - -class SampleScore(IconScoreBase): - def __init__(self, db: IconScoreDatabase) -> None: - super().__init__(db) - self._value = VarDB('value', db, value_type=int) - - def on_install(self, value: int=0) -> None: - super().on_install() - self._value.set(value) - - def on_update(self) -> None: - super().on_update() - - @external - @payable - def func_params_int_with_icx(self, value: int): - pass - - @external - @payable - def func_params_str_with_icx(self, value: str): - pass - - @external - @payable - def func_no_params_with_icx(self): - pass - - @external - @payable - def func_no_params_with_icx_default(self): - pass diff --git a/tests/integrate_test/samples/sample_internal_call_scores/sample_link_score/sample_link_score.py b/tests/integrate_test/samples/sample_internal_call_scores/sample_link_score/sample_link_score.py index 29f473f7c..c63176fa7 100644 --- a/tests/integrate_test/samples/sample_internal_call_scores/sample_link_score/sample_link_score.py +++ b/tests/integrate_test/samples/sample_internal_call_scores/sample_link_score/sample_link_score.py @@ -11,11 +11,11 @@ def get_value(self) -> int: pass @interface def get_db(self) -> IconScoreDatabase: pass - @interface(payable=True) - def fallback_via_internal_call(self, value: icxunit.Loop) -> None: pass + @interface + def fallback_via_internal_call(self) -> None: pass - @interface(payable=True) - def fallback_via_not_payable_internal_call(self, value: icxunit.Loop) -> None: pass + @interface + def fallback_via_not_payable_internal_call(self) -> None: pass class SampleLinkScore(IconScoreBase): @@ -70,12 +70,12 @@ def put_data_to_other_score_db(self): @external(readonly=False) def transfer_icx_to_other_score(self, value: int) -> None: test_interface = self.create_interface_score(self._addr_score.get(), SampleInterface) - test_interface.fallback_via_internal_call(icxunit.Loop(value)) + test_interface.icx(value).fallback_via_internal_call() @external(readonly=False) def transfer_icx_to_other_score_fail(self, value: int) -> None: test_interface = self.create_interface_score(self._addr_score.get(), SampleInterface) - test_interface.fallback_via_not_payable_internal_call(value=icxunit.Loop(value)) + test_interface.icx(value).fallback_via_not_payable_internal_call() @external(readonly=False) @payable diff --git a/tests/integrate_test/test_integrate_score_internal_call.py b/tests/integrate_test/test_integrate_score_internal_call.py index 0ce225da9..7cb1eae3a 100644 --- a/tests/integrate_test/test_integrate_score_internal_call.py +++ b/tests/integrate_test/test_integrate_score_internal_call.py @@ -211,248 +211,3 @@ def test_get_other_score_db(self): func_name="try_get_other_score_db", params={}, expected_status=False) - - def test_transfer_via_internal_call(self): - tx1: dict = self.create_deploy_score_tx(score_root="sample_internal_call_scores", - score_name="sample_score", - from_=self._accounts[0], - to_=SYSTEM_SCORE_ADDRESS) - - tx2: dict = self.create_deploy_score_tx(score_root="sample_internal_call_scores", - score_name="sample_link_score", - from_=self._accounts[0], - to_=SYSTEM_SCORE_ADDRESS) - - tx_results: List['TransactionResult'] = self.process_confirm_block_tx([tx1, tx2]) - score_addr1: 'Address' = tx_results[0].score_address - score_addr2: 'Address' = tx_results[1].score_address - - # callee SCORE = score_addr1 - self.score_call(from_=self._accounts[0], - to_=score_addr2, - func_name="add_score_func", - params={"score_addr": str(score_addr1)}) - - value = 2 * ICX_IN_LOOP - - # increase balance of score_addr2 - self.transfer_icx(self._admin, score_addr2, value) - balance: int = self.get_balance(score_addr2) - self.assertEqual(value, balance) - - # transfer value from score_addr2 to score_addr1 - self.score_call(from_=self._accounts[0], - to_=score_addr2, - func_name="transfer_icx_to_other_score", - params={"value": hex(value)}) - - balance = self.get_balance(score_addr1) - self.assertEqual(value, balance, balance) - balance = self.get_balance(score_addr2) - self.assertEqual(0, balance, balance) - - # transfer fallbacked balance(value) from score_addr2 to score_addr1 in one TX - self.score_call(from_=self._admin, - to_=score_addr2, - value=value, - func_name="transfer_all_icx_to_other_score") - - balance = self.get_balance(score_addr1) - self.assertEqual(value * 2, balance, balance) - balance = self.get_balance(score_addr2) - self.assertEqual(0, balance, balance) - - def test_transfer_via_internal_call_error(self): - tx1: dict = self.create_deploy_score_tx(score_root="sample_internal_call_scores", - score_name="sample_score", - from_=self._accounts[0], - to_=SYSTEM_SCORE_ADDRESS) - - tx2: dict = self.create_deploy_score_tx(score_root="sample_internal_call_scores", - score_name="sample_link_score", - from_=self._accounts[0], - to_=SYSTEM_SCORE_ADDRESS) - - tx_results: List['TransactionResult'] = self.process_confirm_block_tx([tx1, tx2]) - score_addr1: 'Address' = tx_results[0].score_address - score_addr2: 'Address' = tx_results[1].score_address - - # callee SCORE = score_addr1 - self.score_call(from_=self._accounts[0], - to_=score_addr2, - func_name="add_score_func", - params={"score_addr": str(score_addr1)}) - - value = 2 * ICX_IN_LOOP - - # transfer without balance - tx_results = self.score_call(from_=self._accounts[0], - to_=score_addr2, - func_name="transfer_icx_to_other_score", - params={"value": hex(value)}, - expected_status=False) - self.assertTrue(tx_results[0].failure.message.startswith("Out of balance")) - - # increase balance of score_addr2 - self.transfer_icx(self._admin, score_addr2, value) - balance: int = self.get_balance(score_addr2) - self.assertEqual(value, balance) - - # transfer via not payable external function - tx_results = self.score_call(from_=self._accounts[0], - to_=score_addr2, - func_name="transfer_icx_to_other_score_fail", - params={"value": hex(value)}, - expected_status=False) - self.assertTrue(tx_results[0].failure.message.startswith("Method not payable")) - - def test_invalid_interface_score(self): - - score_list = [ - "sample_invalid_score", - "sample_invalid_link_score1", - "sample_invalid_link_score2", - "sample_invalid_link_score3", - "sample_invalid_link_score4", - "sample_invalid_link_score5", - "sample_invalid_link_score6", - "sample_invalid_link_score7", - "sample_invalid_link_score8", - ] - - for score in score_list: - tx: dict = self.create_deploy_score_tx( - score_root="invalid_interface_score", - score_name=score, - from_=self._accounts[0], - to_=SYSTEM_SCORE_ADDRESS - ) - self.process_confirm_block_tx([tx], expected_status=False) - - def test_invalid_interface_score_with_icx(self): - tx1: dict = self.create_deploy_score_tx( - score_root="invalid_interface_score", - score_name="sample_score", - from_=self._accounts[0], - to_=SYSTEM_SCORE_ADDRESS - ) - - tx2: dict = self.create_deploy_score_tx( - score_root="invalid_interface_score", - score_name="sample_link_score", - from_=self._accounts[0], - to_=SYSTEM_SCORE_ADDRESS - ) - - tx_results: List['TransactionResult'] = self.process_confirm_block_tx([tx1, tx2]) - score_addr1: 'Address' = tx_results[0].score_address - score_addr2: 'Address' = tx_results[1].score_address - - # callee SCORE = score_addr1 - self.score_call( - from_=self._accounts[0], - to_=score_addr2, - func_name="add_score_func", - params={"score_addr": str(score_addr1)} - ) - - value = 1 - amount = 2 * ICX_IN_LOOP - - test_list: list = [ - { - "func_name": "test_func_params_int_with_icx", - "params": {"value": hex(value), "amount": hex(-amount)} - } - ] - - for test in test_list: - # increase balance of score_addr2 - self.transfer_icx(self._admin, score_addr2, amount) - balance: int = self.get_balance(score_addr2) - self.assertEqual(amount, balance) - - self.score_call( - from_=self._accounts[0], - to_=score_addr2, - func_name=test["func_name"], - params=test["params"], - expected_status=False - ) - - def test_interface_score_with_icx(self): - tx1: dict = self.create_deploy_score_tx( - score_root="invalid_interface_score", - score_name="sample_score", - from_=self._accounts[0], - to_=SYSTEM_SCORE_ADDRESS - ) - - tx2: dict = self.create_deploy_score_tx( - score_root="invalid_interface_score", - score_name="sample_link_score", - from_=self._accounts[0], - to_=SYSTEM_SCORE_ADDRESS - ) - - tx_results: List['TransactionResult'] = self.process_confirm_block_tx([tx1, tx2]) - score_addr1: 'Address' = tx_results[0].score_address - score_addr2: 'Address' = tx_results[1].score_address - - # callee SCORE = score_addr1 - self.score_call( - from_=self._accounts[0], - to_=score_addr2, - func_name="add_score_func", - params={"score_addr": str(score_addr1)} - ) - - value = 1 - amount = 2 * ICX_IN_LOOP - - tx_results = self.score_call( - from_=self._accounts[0], - to_=score_addr2, - func_name="test_func_params_int_with_icx", - params={"value": hex(value), "amount": hex(amount)}, - expected_status=False - ) - self.assertTrue(tx_results[0].failure.message.startswith("Out of balance")) - - test_list: list = [ - { - "func_name": "test_func_params_int_with_icx", - "params": {"value": hex(value), "amount": hex(amount)} - }, - { - "func_name": "test_func_params_int_with_icx", - "params": {"value": str(value), "amount": hex(amount)} - }, - { - "func_name": "test_func_no_params_with_icx", - "params": {"amount": hex(amount)} - }, - { - "func_name": "test_func_no_params_with_icx_default", - "params": {} - } - ] - - expected_amount: int = 0 - - for test in test_list: - # increase balance of score_addr2 - self.transfer_icx(self._admin, score_addr2, amount) - balance: int = self.get_balance(score_addr2) - self.assertEqual(amount, balance) - - self.score_call( - from_=self._accounts[0], - to_=score_addr2, - func_name=test["func_name"], - params=test["params"] - ) - - expected_amount += amount - balance: int = self.get_balance(score_addr1) - self.assertEqual(expected_amount, balance) diff --git a/tests/integrate_test/test_integrate_score_internal_call_with_icx.py b/tests/integrate_test/test_integrate_score_internal_call_with_icx.py new file mode 100644 index 000000000..e566b37ca --- /dev/null +++ b/tests/integrate_test/test_integrate_score_internal_call_with_icx.py @@ -0,0 +1,240 @@ +# -*- coding: utf-8 -*- + +# Copyright 2018 ICON Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""IconScoreEngine testcase +""" + +import random +from typing import List, Tuple + +from iconservice.base.address import Address +from iconservice.base.address import SYSTEM_SCORE_ADDRESS +from iconservice.base.exception import ExceptionCode +from iconservice.iconscore.icon_score_result import TransactionResult +from iconservice.iconscore.typing.conversion import base_object_to_str +from tests.integrate_test.test_integrate_base import TestIntegrateBase + + +class TestIntegrateScoreInternalCallWithIcx(TestIntegrateBase): + + SCORE_ROOT = "icx_method_chaining" + + def _deploy_sample_scores(self) -> Tuple[Address, Address]: + sender = self._admin + + tx1: dict = self.create_deploy_score_tx( + score_root=self.SCORE_ROOT, + score_name="callee_score", + from_=sender, + to_=SYSTEM_SCORE_ADDRESS + ) + + tx2: dict = self.create_deploy_score_tx( + score_root=self.SCORE_ROOT, + score_name="caller_score", + from_=sender, + to_=SYSTEM_SCORE_ADDRESS + ) + + tx_results: List[TransactionResult] = self.process_confirm_block_tx([tx1, tx2]) + callee: Address = tx_results[0].score_address + caller: Address = tx_results[1].score_address + + self.score_call( + from_=sender, + to_=caller, + func_name="setCallee", + params={"address": str(callee)} + ) + + return callee, caller + + def test_score_internal_call_with_icx(self): + sender = self._admin + callee, caller = self._deploy_sample_scores() + + call_info = ( + ("setBool", "getBool", True), + ("setBytes", "getBytes", b"hello"), + ("setInt", "getInt", 333), + ("setStr", "getStr", "world"), + ("setAddress", "getAddress", self._accounts[0].address), + ) + + amount = random.randint(1, 999) + expected_callee_balance = 0 + for setter, getter, value in call_info: + before_sender_balance: int = self.get_balance(sender) + + tx_results = self.score_call( + from_=sender, + to_=caller, + value=amount, + func_name=setter, + params={"value": base_object_to_str(value)}, + expected_status=True + ) + + expected_callee_balance += amount + fee: int = tx_results[0].step_price * tx_results[0].step_used + + assert self.get_balance(sender) == before_sender_balance - amount - fee + assert self.get_balance(callee) == expected_callee_balance + assert self.get_balance(caller) == 0 + + ret = self.query_score(from_=sender, to_=callee, func_name=getter) + assert ret == value + + def test_non_payable_internal_call(self): + sender = self._admin + callee, caller = self._deploy_sample_scores() + amount = 100 + + before_balance: int = self.get_balance(sender) + + tx_results = self.score_call( + from_=sender, + to_=caller, + value=amount, + func_name="func_with_non_payable_internal_call", + expected_status=False + ) + + tx_result = tx_results[0] + fee: int = tx_result.step_price * tx_result.step_used + + assert tx_result.failure.code == ExceptionCode.METHOD_NOT_PAYABLE + assert self.get_balance(sender) == before_balance - fee + + def test_payable_internal_call(self): + sender = self._admin + callee, caller = self._deploy_sample_scores() + amount = 100 + + before_sender_balance: int = self.get_balance(sender) + before_callee_balance: int = self.get_balance(callee) + before_caller_balance: int = self.get_balance(caller) + + tx_results = self.score_call( + from_=sender, + to_=caller, + value=amount, + func_name="func_with_payable_internal_call", + expected_status=True + ) + + tx_result = tx_results[0] + fee: int = tx_result.step_price * tx_result.step_used + + assert self.get_balance(sender) == before_sender_balance - fee - amount + assert self.get_balance(callee) == before_callee_balance + amount + assert self.get_balance(caller) == before_caller_balance + + def test_non_payable_func_with_negative_icx_internal_call(self): + sender = self._admin + callee, caller = self._deploy_sample_scores() + + self.transfer_icx(from_=sender, to_=caller, value=100) + + tx_results = self.score_call( + from_=sender, + to_=caller, + value=0, + func_name="non_payable_func_with_icx_internal_call", + params={"value": base_object_to_str(-77)}, + expected_status=False + ) + + tx_result = tx_results[0] + assert tx_result.failure.code == ExceptionCode.INVALID_PARAMETER + + def test_non_payable_func_with_positive_icx_internal_call(self): + sender = self._admin + callee, caller = self._deploy_sample_scores() + self.transfer_icx(from_=sender, to_=caller, value=1000) + + amount = random.randint(1, 499) + before_sender_balance: int = self.get_balance(sender) + before_caller_balance: int = self.get_balance(caller) + before_callee_balance: int = self.get_balance(callee) + + # Caller will call a method of callee with amount icx + tx_results = self.score_call( + from_=sender, + to_=caller, + value=0, + func_name="non_payable_func_with_icx_internal_call", + params={"value": base_object_to_str(amount)}, + expected_status=True + ) + + tx_result = tx_results[0] + fee: int = tx_result.step_price * tx_result.step_used + + assert self.get_balance(sender) == before_sender_balance - fee + assert self.get_balance(caller) == before_caller_balance - amount + assert self.get_balance(callee) == before_callee_balance + amount + + def test_non_payable_func_with_out_of_balance_internal_call(self): + sender = self._admin + callee, caller = self._deploy_sample_scores() + self.transfer_icx(from_=sender, to_=caller, value=1000) + + amount = 2000 + before_sender_balance: int = self.get_balance(sender) + before_caller_balance: int = self.get_balance(caller) + before_callee_balance: int = self.get_balance(callee) + + # Caller will try to call a method of callee with icx + # which is larger than caller owns + # So this tx should occur out of balance exception + tx_results = self.score_call( + from_=sender, + to_=caller, + value=0, + func_name="non_payable_func_with_icx_internal_call", + params={"value": base_object_to_str(amount)}, + expected_status=False + ) + + tx_result = tx_results[0] + assert tx_result.failure.code == ExceptionCode.OUT_OF_BALANCE + + fee: int = tx_result.step_price * tx_result.step_used + + assert self.get_balance(sender) == before_sender_balance - fee + assert self.get_balance(caller) == before_caller_balance + assert self.get_balance(callee) == before_callee_balance + + def test_fallback_with_icx_internal_call(self): + sender = self._admin + callee, caller = self._deploy_sample_scores() + + value = 500 + half_value = value // 2 + before_sender_balance: int = self.get_balance(sender) + before_caller_balance: int = self.get_balance(caller) + before_callee_balance: int = self.get_balance(callee) + + # Caller passes a half of icx which it gets from fallback() to callee + tx_results = self.transfer_icx(from_=sender, to_=caller, value=value) + + tx_result = tx_results[0] + fee: int = tx_result.step_price * tx_result.step_used + + assert self.get_balance(sender) == before_sender_balance - fee - value + assert self.get_balance(caller) == before_caller_balance + half_value + assert self.get_balance(callee) == before_callee_balance + half_value diff --git a/tests/legacy_unittest/prep/test_prep_address_converter.py b/tests/legacy_unittest/prep/test_prep_address_converter.py index ebc1d00a8..72f48d5aa 100644 --- a/tests/legacy_unittest/prep/test_prep_address_converter.py +++ b/tests/legacy_unittest/prep/test_prep_address_converter.py @@ -46,7 +46,7 @@ def test_add_node_address(self): address = self.converter.get_prep_address_from_node_address(node_address) assert address == prep_address - self.converter.delete_node_address(node_address) + self.converter._delete_node_address(node_address) address = self.converter.get_prep_address_from_node_address(node_address) assert address == node_address assert address != prep_address @@ -81,6 +81,31 @@ def test_replace_node_address(self): assert len(converter._prev_node_address_mapper) == 1 assert len(converter._node_address_mapper) == 1 + def test_delete_node_address(self): + converter = self.converter + node_address = self.node_addresses[0] + prep_address = self.prep_addresses[0] + + # Confirm that 2 addresses are different + assert node_address != prep_address + + # Check whether old_node_address is not added to converter + address = self.converter.get_prep_address_from_node_address(node_address) + assert address == node_address + + # Add old_node_address + converter.add_node_address(node_address, prep_address) + address = self.converter.get_prep_address_from_node_address(node_address) + assert address == prep_address + + converter.delete_node_address(node_address, prep_address) + address = converter.get_prep_address_from_node_address(node_address) + assert address == prep_address + assert node_address in converter._prev_node_address_mapper + assert node_address not in converter._node_address_mapper + assert len(converter._prev_node_address_mapper) == 1 + assert len(converter._node_address_mapper) == 0 + def test_copy(self): converter = self.converter old_node_address = self.node_addresses[0] @@ -106,7 +131,7 @@ def test_copy(self): assert id(new_converter._prev_node_address_mapper) != id(converter._prev_node_address_mapper) assert id(new_converter._node_address_mapper) != id(converter._node_address_mapper) - new_converter.delete_node_address(new_node_address) + new_converter._delete_node_address(new_node_address) assert new_node_address == new_converter.get_prep_address_from_node_address(new_node_address) assert prep_address == converter.get_prep_address_from_node_address(new_node_address)