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

Hotfix/1.7.2 #490

Merged
merged 5 commits into from
Aug 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
}
Loading