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

Hotfix/1.7.1 #486

Merged
merged 7 commits into from
Jul 31, 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
38 changes: 31 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
language: python
dist: bionic
python:
- "3.7"

branches:
only:
- master
- develop
- /^release[/-].*$/
- /^(release|hotfix)[/-].*$/
- /^(\d+)(\.\d+){1,2}((a|b|rc)?\d*)?(\.?(post|dev)\d*)?/
- deploy-test

install:
- go get github.com/icon-project/rewardcalculator/cmd/icon_rc
Expand All @@ -18,9 +21,30 @@ script:
- python -m pytest -ra

deploy:
provider: pypi
distributions: sdist bdist_wheel
user: iconfoundation
password: $PYPI_PW
on:
branch: master
- provider: pypi
edge: true
distributions: sdist bdist_wheel
user: $PYPI_USER
password: $PYPI_PW
on:
tags: true
all_branches: true
condition: $TRAVIS_TAG =~ ^([0-9]+)(\.[0-9]+){1,2}$
- provider: pypi
edge: true
server: https://test.pypi.org/legacy/
distributions: sdist bdist_wheel
user: $PYPI_USER
password: $PYPI_PW
skip_existing: true
on:
tags: true
all_branches: true
condition: $TRAVIS_TAG =~ ^([0-9]+)(\.[0-9]+){1,2}((a|b|rc)+[0-9]*)+(\.?(post|dev)[0-9]*)?

notifications:
slack:
rooms:
- secure: gKVeRcXlQHJ/L/j1jiYNr2QOyQWUa+iw6RIEl0VJHFYFet0lQhGBkqKqnonQlmR9z+6P3/s1eWX15ZFwQYgtvwX+4ch03j1rop8n1inLbyA4IAfCThWn0IjKcFf6SsEI54tB/XC099uX3TwPKlLD1fxlawxwxbN0RCKx/vCVIcDDcPQmg9ICkiU0LO14rAsnUrtZua6gKgFAevppURwD1n7GEz2oc/kXG/aLKBOqJuIpeaS5FYpV2uuPevlOs5geyRsA5TiJuldCqfzXbDNL+TAR9NUlBym7RuJL763Q3ywPMziwaWV/u0EHEQfcCjP7ifdPNgriwwvJqQ0VU1RkPNuYDuY/QEEcSelGS0yD6onPfh8ggJIyPxNJgoZbYwN/+KzJHd1hpCC4xc2xIJo3lF9DOODJ+pL36CRBlluKJDYXWsBaksGd3LSrmTbfSHsSAU53QmWIMSQ8XzL1dp6Vjoksz22mBLUL5J967ZwodLJVTOhZc0t9KMZ+8EryBDFHjuLvvUrXfVHDMKrqh4xBCrsLXptokAx8Yv0ehTt0hHCdzMe7Q0bOopa4/p8BV7CZB+8aG6J+5K04w7tJbC6QhFUgOEpLkngI5VU8Q+nFfc92Ucu3iUeSmJVuidoDN7TKebdo/qn0TheD8+LSjiY+TA+lq1MQATj3HkS0L1R1b1Q=
on_success: change
on_failure: always
11 changes: 8 additions & 3 deletions iconservice/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@
from .icon_constant import IconServiceFlag
from .iconscore.icon_container_db import VarDB, DictDB, ArrayDB
from .iconscore.icon_score_base import interface, eventlog, external, payable, IconScoreBase, IconScoreDatabase
from .iconscore.icon_score_base2 import (InterfaceScore, revert, sha3_256, sha_256, json_loads, json_dumps,
get_main_prep_info, get_sub_prep_info, recover_key,
create_address_with_key, create_interface_score)
from .iconscore.icon_score_base2 import (
InterfaceScore, revert, sha3_256, sha_256, json_loads, json_dumps,
get_main_prep_info, get_sub_prep_info, recover_key,
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.0'
__version__ = '1.7.1'
3 changes: 2 additions & 1 deletion iconservice/icon_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
ConfigKey, TERM_PERIOD, IISS_DAY_BLOCK, PREP_MAIN_PREPS,
PREP_MAIN_AND_SUB_PREPS, PENALTY_GRACE_PERIOD, LOW_PRODUCTIVITY_PENALTY_THRESHOLD,
BLOCK_VALIDATION_PENALTY_THRESHOLD, BACKUP_FILES, BLOCK_INVOKE_TIMEOUT_S,
IISS_INITIAL_IREP, PREP_REGISTRATION_FEE)
IISS_INITIAL_IREP, PREP_REGISTRATION_FEE, UNSTAKE_SLOT_MAX)

_TAG = "CFG"
ConfigValue = Union[bool, dict, float, int, str]
Expand Down Expand Up @@ -76,6 +76,7 @@
ConfigKey.BACKUP_FILES: BACKUP_FILES,
ConfigKey.BLOCK_INVOKE_TIMEOUT: BLOCK_INVOKE_TIMEOUT_S,
ConfigKey.TBEARS_MODE: False,
ConfigKey.UNSTAKE_SLOT_MAX: UNSTAKE_SLOT_MAX,
}


Expand Down
2 changes: 2 additions & 0 deletions iconservice/icon_constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ class ConfigKey:
# Block invoke timeout in second
BLOCK_INVOKE_TIMEOUT = "blockInvokeTimeout"

UNSTAKE_SLOT_MAX = "unstakeSlotMax"


class EnableThreadFlag(IntFlag):
INVOKE = 1
Expand Down
1 change: 1 addition & 0 deletions iconservice/icon_service_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ def open(self, conf: dict):
IconScoreContext.step_trace_flag = conf[ConfigKey.STEP_TRACE_FLAG]
IconScoreContext.log_level = conf[ConfigKey.LOG][ConfigKey.LOG_LEVEL]
IconScoreContext.precommitdata_log_flag = conf[ConfigKey.PRECOMMIT_DATA_LOG_FLAG]
IconScoreContext.unstake_slot_max = conf[ConfigKey.UNSTAKE_SLOT_MAX]
self._init_component_context()

# Recover incomplete state on wal and rollback process
Expand Down
48 changes: 46 additions & 2 deletions iconservice/iconscore/icon_score_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
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 @@ -63,13 +64,16 @@
INDEXED_ARGS_LIMIT = 3


def interface(func):
def interface(func=None, *, payable=False):
"""
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):
raise IllegalFormatException(FORMAT_IS_NOT_FUNCTION_OBJECT.format(func, cls_name))
Expand All @@ -79,6 +83,27 @@ def interface(func):

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 @@ -87,9 +112,28 @@ def __wrapper(calling_obj: "InterfaceScore", *args, **kwargs):

context = ContextContainer._get_context()
addr_to = calling_obj.addr_to
amount = calling_obj.value
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

if addr_to is None:
raise InvalidInterfaceException('Cannot create an interface SCORE with a None address')

Expand Down
18 changes: 1 addition & 17 deletions iconservice/iconscore/icon_score_base2.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ def __init__(self, addr_to: 'Address'):
A Python init function. Invoked when the contract call create_interface_score()
"""
self.__addr_to = addr_to
self.__value = 0

@property
def addr_to(self) -> 'Address':
Expand All @@ -64,22 +63,6 @@ def addr_to(self) -> 'Address':
"""
return self.__addr_to

@property
def value(self) -> int:
"""
The amount of ICX that the caller SCORE attempts to transfer to the callee SCORE when invoke interface method.
The value is retained till setting again. If don't want to transfer ICX, reset the value to zero.

:Getter: Returns amount of ICX in loop
:Setter: Sets amount of ICX in loop
:type: int
"""
return self.__value

@value.setter
def value(self, value: int):
self.__value = value


class Block(object):
def __init__(self, block_height: int, timestamp: int) -> None:
Expand Down Expand Up @@ -394,3 +377,4 @@ 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 @@ -32,7 +32,7 @@
from ..icon_constant import (
IconScoreContextType, IconScoreFuncType, TERM_PERIOD, PRepGrade, PREP_MAIN_PREPS, PREP_MAIN_AND_SUB_PREPS,
TermFlag, PRepStatus,
Revision, PRepFlag, RevisionChangedFlag)
Revision, PRepFlag, RevisionChangedFlag, UNSTAKE_SLOT_MAX)
from ..icx.issue.regulator import Regulator

if TYPE_CHECKING:
Expand Down Expand Up @@ -68,6 +68,7 @@ class IconScoreContext(ABC):
precommitdata_log_flag = False
step_trace_flag: bool = False
log_level: str = None
unstake_slot_max: int = UNSTAKE_SLOT_MAX

"""Contains the useful information to process user's JSON-RPC request
"""
Expand Down
3 changes: 3 additions & 0 deletions iconservice/iconscore/icxunit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

class Loop(int):
pass
4 changes: 4 additions & 0 deletions iconservice/iconscore/system_score.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ class SystemScore(IconScoreBase):
def IScoreClaimed(self, iscore: int, icx: int):
pass

@eventlog(indexed=1)
def IScoreClaimedV2(self, address: Address, iscore: int, icx: int):
pass

@eventlog
def PRepRegistered(self, address: Address):
pass
Expand Down
10 changes: 6 additions & 4 deletions iconservice/icx/icx_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from .delegation_part import DelegationPart
from .stake_part import StakePart
from ..base.address import Address
from ..iconscore.icon_score_context import IconScoreContext


class Account(object):
Expand Down Expand Up @@ -145,7 +146,7 @@ def normalize(self, revision: int):
self.coin_part.toggle_has_unstake(False)
self.coin_part.deposit(balance)

def set_stake(self, value: int, unstake_lock_period: int, revision: int):
def set_stake(self, context: "IconScoreContext", value: int, unstake_lock_period: int):
if self.coin_part is None or self.stake_part is None:
raise InvalidParamsException('Failed to stake: InvalidAccount')

Expand All @@ -168,10 +169,11 @@ def set_stake(self, value: int, unstake_lock_period: int, revision: int):
else:
unlock_block_height: int = self._current_block_height + unstake_lock_period
self.coin_part.toggle_has_unstake(True)
if revision >= Revision.MULTIPLE_UNSTAKE.value:
self.stake_part.set_unstakes_info(unlock_block_height, self.total_stake - value)
if context.revision >= Revision.MULTIPLE_UNSTAKE.value:
self.stake_part.set_unstakes_info(unlock_block_height,
-offset, context.unstake_slot_max)
else:
self.stake_part.set_unstake(unlock_block_height, self.total_stake - value)
self.stake_part.set_unstake(unlock_block_height, -offset)

def update_delegated_amount(self, offset: int):
if self.delegation_part is None:
Expand Down
33 changes: 20 additions & 13 deletions iconservice/icx/stake_part.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

from .base_part import BasePart, BasePartState
from ..base.exception import InvalidParamsException
from ..icon_constant import Revision, UNSTAKE_SLOT_MAX
from ..icon_constant import Revision
from ..utils.msgpack_for_db import MsgPackForDB

if TYPE_CHECKING:
Expand Down Expand Up @@ -112,15 +112,15 @@ def set_unstake(self, block_height: int, value: int):

self.set_dirty(True)

def set_unstakes_info(self, block_height: int, new_total_unstake: int):
def set_unstakes_info(self, block_height: int, new_total_unstake: int, slot_max: int):
total_stake = self.total_stake

if new_total_unstake < self.total_unstake:
self.withdraw_unstake(self.total_unstake - new_total_unstake)

elif self.total_unstake < new_total_unstake:
increment_unstake = new_total_unstake - self.total_unstake
if len(self._unstakes_info) == UNSTAKE_SLOT_MAX:
if len(self._unstakes_info) == slot_max:
old_value_pair = self._unstakes_info.pop()
increment_unstake += old_value_pair[0]
unstake_block_height = max(old_value_pair[1], block_height)
Expand Down Expand Up @@ -172,12 +172,17 @@ def normalize(self, block_height: int, revision: int) -> int:
self._unstake = 0
self._unstake_block_height = 0

if len(self._unstakes_info) and self._unstakes_info[0][1] < block_height:
total_unstake = self._total_unstake()
self._unstakes_info = [info for info in self._unstakes_info if info[1] >= block_height]
new_total_unstake = self._total_unstake()
state |= BasePartState.DIRTY
unstake = total_unstake - new_total_unstake
size = len(self._unstakes_info)
for i in range(size):
info = self._unstakes_info[0]
if info[1] >= block_height:
if i > 0:
state |= BasePartState.DIRTY
break

# Remove unstatke_info of which lock period is already expired
self._unstakes_info.pop(0)
unstake += info[0]

else:
if 0 < self._unstake_block_height < block_height:
Expand Down Expand Up @@ -255,7 +260,9 @@ def __ne__(self, other) -> bool:
return not self.__eq__(other)

def get_unstake_slot_index(self, block_height: int):
for index in range(len(self.unstakes_info)):
if block_height <= self.unstakes_info[index][1]:
return index
return len(self.unstakes_info)
unstakes_info = self._unstakes_info
length = len(unstakes_info)
for index in reversed(range(length)):
if block_height >= unstakes_info[index][1]:
return index + 1
return 0
Loading