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

Release 1.6.1 #434

Merged
merged 19 commits into from
Apr 1, 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: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.6.0
1.6.1
2 changes: 1 addition & 1 deletion iconservice/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
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, json_loads, json_dumps,
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_system_score_base import IconSystemScoreBase
34 changes: 21 additions & 13 deletions iconservice/database/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
from typing import TYPE_CHECKING, Optional, Tuple, Iterable

import plyvel

from iconcommons.logger import Logger

from .batch import TransactionBatchValue
from ..base.exception import DatabaseException, InvalidParamsException, AccessDeniedException
from ..icon_constant import ICON_DB_LOG_TAG
Expand Down Expand Up @@ -384,6 +384,14 @@ def __init__(self,
self._context_db = context_db
self._observer: Optional[DatabaseObserver] = None

self._prefix_hash_key: bytes = self._make_prefix_hash_key()

def _make_prefix_hash_key(self) -> bytes:
data = [self.address.to_bytes()]
if self._prefix is not None:
data.append(self._prefix)
return b'|'.join(data)

def get(self, key: bytes) -> bytes:
"""
Gets the value for the specified key
Expand Down Expand Up @@ -428,7 +436,7 @@ def get_sub_db(self, prefix: bytes) -> 'IconScoreSubDatabase':
'prefix is None in IconScoreDatabase.get_sub_db()')

if self._prefix is not None:
prefix = b'|'.join([self._prefix, prefix])
prefix = b'|'.join((self._prefix, prefix))

return IconScoreSubDatabase(self.address, self, prefix)

Expand Down Expand Up @@ -460,12 +468,8 @@ def _hash_key(self, key: bytes) -> bytes:
:params key: key passed by SCORE
:return: key bytes
"""
data = [self.address.to_bytes()]
if self._prefix is not None:
data.append(self._prefix)
data.append(key)

return b'|'.join(data)
return b'|'.join((self._prefix_hash_key, key))

def _validate_ownership(self):
"""Prevent a SCORE from accessing the database of another SCORE
Expand All @@ -490,6 +494,14 @@ def __init__(self, address: 'Address', score_db: 'IconScoreDatabase', prefix: by
self._prefix = prefix
self._score_db = score_db

self._prefix_hash_key: bytes = self._make_prefix_hash_key()

def _make_prefix_hash_key(self) -> bytes:
data = []
if self._prefix is not None:
data.append(self._prefix)
return b'|'.join(data)

def get(self, key: bytes) -> bytes:
"""
Gets the value for the specified key
Expand Down Expand Up @@ -521,7 +533,7 @@ def get_sub_db(self, prefix: bytes) -> 'IconScoreSubDatabase':
raise InvalidParamsException("Invalid prefix")

if self._prefix is not None:
prefix = b'|'.join([self._prefix, prefix])
prefix = b'|'.join((self._prefix, prefix))

return IconScoreSubDatabase(self.address, self._score_db, prefix)

Expand All @@ -544,9 +556,5 @@ def _hash_key(self, key: bytes) -> bytes:
:params key: key passed by SCORE
:return: key bytes
"""
data = []
if self._prefix is not None:
data.append(self._prefix)
data.append(key)

return b'|'.join(data)
return b'|'.join((self._prefix_hash_key, key))
5 changes: 3 additions & 2 deletions iconservice/icon_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from .icon_constant import (
ConfigKey, ICX_IN_LOOP, 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_VALIDATION_PENALTY_THRESHOLD, BACKUP_FILES, BLOCK_INVOKE_TIMEOUT_S
)

default_icon_config = {
Expand Down Expand Up @@ -61,5 +61,6 @@
ConfigKey.BLOCK_VALIDATION_PENALTY_THRESHOLD: BLOCK_VALIDATION_PENALTY_THRESHOLD,
ConfigKey.STEP_TRACE_FLAG: False,
ConfigKey.PRECOMMIT_DATA_LOG_FLAG: False,
ConfigKey.BACKUP_FILES: BACKUP_FILES
ConfigKey.BACKUP_FILES: BACKUP_FILES,
ConfigKey.BLOCK_INVOKE_TIMEOUT: BLOCK_INVOKE_TIMEOUT_S
}
5 changes: 5 additions & 0 deletions iconservice/icon_constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ class ConfigKey:
# The maximum number of backup files for rollback
BACKUP_FILES = "backupFiles"

# Block invoke timeout in second
BLOCK_INVOKE_TIMEOUT = "blockInvokeTimeout"


class EnableThreadFlag(IntFlag):
INVOKE = 1
Expand Down Expand Up @@ -306,6 +309,8 @@ class DeployState(IntEnum):

BACKUP_FILES = 10

BLOCK_INVOKE_TIMEOUT_S = 15


class RCStatus(IntEnum):
NOT_READY = 0
Expand Down
52 changes: 50 additions & 2 deletions iconservice/icon_service_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
ICON_DEX_DB_NAME, ICON_SERVICE_LOG_TAG, IconServiceFlag, ConfigKey,
IISS_METHOD_TABLE, PREP_METHOD_TABLE, NEW_METHOD_TABLE, Revision, BASE_TRANSACTION_INDEX,
IISS_DB, IISS_INITIAL_IREP, DEBUG_METHOD_TABLE, PREP_MAIN_PREPS, PREP_MAIN_AND_SUB_PREPS,
ISCORE_EXCHANGE_RATE, STEP_LOG_TAG, TERM_PERIOD, BlockVoteStatus, WAL_LOG_TAG, ROLLBACK_LOG_TAG
ISCORE_EXCHANGE_RATE, STEP_LOG_TAG, TERM_PERIOD, BlockVoteStatus, WAL_LOG_TAG, ROLLBACK_LOG_TAG,
BLOCK_INVOKE_TIMEOUT_S
)
from .iconscore.icon_pre_validator import IconPreValidator
from .iconscore.icon_score_class_loader import IconScoreClassLoader
Expand Down Expand Up @@ -75,6 +76,7 @@
from .utils import sha3_256, int_to_bytes, ContextEngine, ContextStorage
from .utils import to_camel_case, bytes_to_hex
from .utils.bloom import BloomFilter
from .utils.timer import Timer

if TYPE_CHECKING:
from .iconscore.icon_score_event_log import EventLog
Expand Down Expand Up @@ -112,6 +114,7 @@ def __init__(self):
self._backup_manager: Optional[BackupManager] = None
self._backup_cleaner: Optional[BackupCleaner] = None
self._conf: Optional[Dict[str, Union[str, int]]] = None
self._block_invoke_timeout_s: int = BLOCK_INVOKE_TIMEOUT_S

# JSON-RPC handlers
self._handlers = {
Expand Down Expand Up @@ -215,6 +218,8 @@ def open(self, conf: 'IconConfig'):
context, Address.from_string(conf[ConfigKey.BUILTIN_SCORE_OWNER]))
self._init_global_value_by_governance_score(context)

self._set_block_invoke_timeout(conf)

# DO NOT change the values in conf
self._conf = conf

Expand Down Expand Up @@ -470,7 +475,6 @@ def invoke(self,
:param is_block_editable: boolean which imply whether creating base transaction or not
:return: (TransactionResult[], bytes, added transaction{}, main prep as dict{})
"""

# If the block has already been processed,
# return the result from PrecommitDataManager
precommit_data: 'PrecommitData' = self._precommit_data_manager.get(block.hash)
Expand Down Expand Up @@ -524,7 +528,18 @@ def invoke(self,
context.block_batch.update(context.tx_batch)
context.tx_batch.clear()
else:
tx_timer = Timer()
tx_timer.start()

for index, tx_request in enumerate(tx_requests):
# Adjust the number of transactions in a block to make sure that
# a leader can broadcast a block candidate to validators in a specific period.
if is_block_editable and not self._continue_to_invoke(tx_request, tx_timer):
Logger.info(
tag=self.TAG,
msg=f"Stop to invoke remaining transactions: {index} / {len(tx_requests)}")
break

if index == BASE_TRANSACTION_INDEX and context.is_decentralized():
if not tx_request['params'].get('dataType') == "base":
raise InvalidBaseTransactionException(
Expand Down Expand Up @@ -2388,3 +2403,36 @@ def _finish_to_recover_rollback(self):
end_block_height=metadata.last_block.height - 1)

Logger.debug(tag=self.TAG, msg="_finish_to_recover_rollback() end")

def _set_block_invoke_timeout(self, conf: Dict[str, Union[str, int]]):
try:
timeout_s: int = conf[ConfigKey.BLOCK_INVOKE_TIMEOUT]
if timeout_s > 0:
self._block_invoke_timeout_s = timeout_s
except:
pass

Logger.info(tag=self.TAG, msg=f"{ConfigKey.BLOCK_INVOKE_TIMEOUT}: {self._block_invoke_timeout_s}")

def _continue_to_invoke(self, tx_request: Dict, tx_timer: 'Timer') -> bool:
"""If this is a block created by a leader,
check to continue transaction invoking with block_invoke_timeout

:param tx_request:
:param tx_timer:
:return:
"""
to: Optional['Address'] = tx_request["params"].get("to")

# Skip EOA to EOA coin transfer in execution time check
if to and to.is_contract:
if tx_timer.duration >= self._block_invoke_timeout_s:
Logger.info(
tag=self.TAG,
msg=f"Stop transaction invoking: "
f"duration={tx_timer.duration} "
f"block_invoke_timeout={self._block_invoke_timeout_s}"
)
return False

return True
Loading