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 #434 from icon-project/release-1.6.1
Browse files Browse the repository at this point in the history
* Adjust tx count in a block with execution time
* Raise an exception on DictDB iteration
* Fix a minor bug in Fee-2.0
* Optimize ArrayDB, DictDB and VarDB used for SCORE development
* Support sha_256 function in SCORE
  • Loading branch information
goldworm-icon authored Apr 1, 2020
2 parents 982f7fb + 56b3460 commit eefc37c
Show file tree
Hide file tree
Showing 20 changed files with 679 additions and 83 deletions.
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

0 comments on commit eefc37c

Please sign in to comment.