Skip to content
This repository has been archived by the owner on Dec 15, 2021. It is now read-only.

Commit

Permalink
Merge pull request #489 from icon-project/hotfix/1.7.2
Browse files Browse the repository at this point in the history
Hotfix/1.7.2
  • Loading branch information
goldworm-icon committed Aug 3, 2020
2 parents b72762d + 521612f commit cb3b641
Show file tree
Hide file tree
Showing 40 changed files with 626 additions and 737 deletions.
2 changes: 0 additions & 2 deletions iconservice/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__
2 changes: 1 addition & 1 deletion iconservice/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.7.1'
__version__ = '1.7.2'
4 changes: 2 additions & 2 deletions iconservice/icon_service_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
Expand Down
47 changes: 3 additions & 44 deletions iconservice/iconscore/icon_score_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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):
Expand All @@ -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):
Expand All @@ -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')
Expand Down
15 changes: 14 additions & 1 deletion iconservice/iconscore/icon_score_base2.py
Original file line number Diff line number Diff line change
Expand Up @@ -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':
Expand All @@ -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:
Expand Down Expand Up @@ -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)

3 changes: 2 additions & 1 deletion iconservice/iconscore/icon_score_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 0 additions & 3 deletions iconservice/iconscore/icxunit.py

This file was deleted.

4 changes: 4 additions & 0 deletions iconservice/prep/penalty_imposer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 10 additions & 5 deletions iconservice/prep/prep_address_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand All @@ -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':
Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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)
Expand Down Expand Up @@ -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)

Expand All @@ -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)
Expand Down Expand Up @@ -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}")
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"version": "0.0.1",
"main_module": "score",
"main_score": "Score"
}

0 comments on commit cb3b641

Please sign in to comment.