def __init_score_helper(self): """ Initialize ScoreHelper(). ScoreHelper is special module to capsulize SCORE operation. """ if self.__score_helper is None: self.__score_helper = ScoreHelper()
def test_score_helper_load_databases(self): helper = ScoreHelper() helper.peer_id = 'test_score_helper_load_databases' sqlite_conn = helper.load_database('sqlite_test') self.assertIsNotNone(sqlite_conn) self.assertIsNotNone(sqlite_conn.cursor()) leveldb_conn = helper.load_database('leveldb_test', ScoreDatabaseType.leveldb) self.assertIsNotNone(leveldb_conn) self.assertIsNotNone(sqlite_conn.cursor())
def __init_db(self): helper = ScoreHelper() if self.__contract_db is None: logging.debug(self.LOG_PREFIX + "Init DB(%s)", self.CONTRACT_DB_ID) self.__contract_db = LocalDB(self.CONTRACT_DB_ID) if self.__user_db is None: logging.debug(self.LOG_PREFIX + "Init DB(%s)", self.USER_DB_ID) self.__user_db = LocalDB(self.USER_DB_ID)
def test_score_helper_load_databases(self, score_service_mock): # get peer status Mockup score_service_mock.get_peer_status = lambda: json.loads( '{"total_tx": "0", "block_height": "0", \ "status": {"peer_type": "0", "total_tx": 0, "consensus": "siever", "status": "Service is online: 0", \ "block_height": 0, "audience_count": 0, "peer_id": "d3694dcc-24ff-11e7-b0d1-0242ac110001"}}' ) score_service_mock.get_peer_id = lambda: 'test_score_helper_load_databases' ObjectManager().score_service = score_service_mock helper = ScoreHelper() sqlite_conn = helper.load_database('sqlite_test') self.assertIsNotNone(sqlite_conn) self.assertIsNotNone(sqlite_conn.cursor()) leveldb_conn = helper.load_database('leveldb_test', ScoreDatabaseType.leveldb) self.assertIsNotNone(leveldb_conn) self.assertIsNotNone(sqlite_conn.cursor())
def write_precommit_state(self, params): with self.__precommit_usage_lock: try: commit_request = json.loads(params) ScoreHelper().commit_block_state(commit_request['block_height'], commit_request['block_hash']) self.__remove_temp_invoke_results(commit_request['block_height']) return loopchain_pb2.Message(code=message_code.Response.success) except Exception as e: logging.exception(f"score db commit error : {params}\n" f"cause : {e}") util.exit_and_msg("score db commit fail") return loopchain_pb2.Message(code=message_code.Response.fail)
def change_block_hash(self, params): with self.__precommit_usage_lock: try: change_block_info = json.loads(params) ScoreHelper().change_block_hash(block_height=change_block_info['block_height'], old_block_hash=change_block_info['old_block_hash'], new_block_hash=change_block_info['new_block_hash']) self.__remove_fail_invoke_result_to_new_block_invoke_result(change_block_info) return loopchain_pb2.Message(code=message_code.Response.success) except Exception as e: logging.exception(f"score change block hash fail : {params}\n" f"cause : {e}") # change block_hash fail often because next block commit # util.exit_and_msg("score db proxy change block_hash fail please restart") return loopchain_pb2.Message(code=message_code.Response.fail)
def __init__(self, score_info=None): # TODO:Change 'YOUR_SCORE_DB' your own DB name. self.__db_name = "YOUR_SCORE_DB" # Call base class's __init__. ScoreBase.__init__(self, score_info) # DO NOT CHANGE THIS BLOCK. # ==================================== # Load package.json file for info() function. self.__score_info = None if self.__score_info is None: with open(join(dirname(__file__), ScoreBase.PACKAGE_FILE), "r") as f: self.__score_info = json.loads(f.read()) f.close() else: self.__score_info = score_info # Initialize ScoreBase module. self.__score_helper = ScoreHelper() # Initialize SCOREBusinessLogic module. self.__my_business_logic = SCOREBusinessLogic() # Map functions in package.json. for e in self.__score_info["function"]["invoke"]: function_name = e["method"] self.__invoke_function_map[function_name] = getattr( self.__my_business_logic, function_name) for e in self.__score_info["function"]["query"]: function_name = e["method"] self.__query_function_map[function_name] = getattr( self.__my_business_logic, function_name)
def __init__(self): # User can use several DB instances. self.__db = ScoreHelperDatabase("MY_OWN_DB", ScoreHelper())
def genesis_invoke(self, block_pickled): logging.debug("ScoreService handler genesis invoke...") results = {} # dict key code_key = 'code' error_message_key = 'message' if not self._score_service.score: logging.error("There is no score!!") return loopchain_pb2.Message(code=message_code.Response.fail) else: block = pickle.loads(block_pickled) logging.debug('tx_list_length : %d ', block.confirmed_tx_len) ScoreHelper().init_invoke(block) for transaction in block.confirmed_transaction_list: if isinstance(transaction, Transaction) and transaction.tx_hash is not None: tx_hash = transaction.tx_hash results[tx_hash] = {} # put score invoke result to results[tx_hash] try: plugin_result = self._score_service.score_plugin.genesis_invoke( transaction=transaction, block=block) if plugin_result == PluginReturns.CONTINUE: plugin_result = self._score_service.score.genesis_invoke( transaction, block) invoke_result = plugin_result if invoke_result is None: results[tx_hash] = { code_key: message_code.Response.success } ScoreHelper().commit_tx_state() else: if code_key not in invoke_result: code_not_return = "Score not return code" if error_message_key in invoke_result: raise ScoreInvokeError( code_not_return + ": " + invoke_result[error_message_key]) raise ScoreInvokeError(code_not_return) elif invoke_result[ code_key] == message_code.Response.success: ScoreHelper().commit_tx_state() elif error_message_key in invoke_result: results[tx_hash][ error_message_key] = invoke_result[ error_message_key] ScoreHelper().reset_tx_state() results[tx_hash][code_key] = invoke_result[ code_key] # if score raise exception result to fail and put error message except Exception as e: logging.exception("tx %s score invoke is fail!! : %s ", str(tx_hash), e) ScoreHelper().reset_tx_state() results[tx_hash][code_key] = ScoreResponse.EXCEPTION results[tx_hash][error_message_key] = str(e) continue util.apm_event( self._score_service.peer_id, { 'event_type': 'GenesisInvoke', 'peer_id': self._score_service.peer_id, 'peer_name': conf.PEER_NAME, 'channel_name': self._score_service.channel_name, 'data': { 'request_peer_id': None, 'tx_data': transaction.get_genesis_tx_data(), 'invoke_result': invoke_result } }) logging.debug('results : %s', str(results)) ScoreHelper().precommit_state() meta = json.dumps(results) return loopchain_pb2.Message(code=message_code.Response.success, meta=meta)
def score_invoke(self, block: Block): logging.debug("ScoreService handler invoke...") invoke_result_list = {} code_key = 'code' error_message_key = 'message' with self.__precommit_usage_lock: if not self._score_service.score: logging.error("There is no score!!") return loopchain_pb2.Message(code=message_code.Response.fail) else: # get invoke_data if before invoke same block saved_results = self.__temp_invoke_results[block.height].get( block.block_hash) logging.debug( f"saved invoke result {block.height}, {block.block_hash} : {saved_results}" ) if saved_results: commit_state = ScoreHelper().get_block_commit_state( block.height, block.block_hash) return loopchain_pb2.Message( code=message_code.Response.success, meta=json.dumps(saved_results), object=pickle.dumps(commit_state)) logging.debug('tx_list_length : %d ', block.confirmed_tx_len) ScoreHelper().init_invoke(block) for transaction in block.confirmed_transaction_list: if isinstance( transaction, Transaction) and transaction.tx_hash is not None: tx_hash = transaction.tx_hash invoke_result_list[tx_hash] = {} # put score invoke result to results[tx_hash] invoke_result = {} try: plugin_result = self._score_service.score_plugin.invoke( transaction=transaction, block=block) if plugin_result == PluginReturns.CONTINUE: plugin_result = self._score_service.score.invoke( transaction, block) invoke_result = plugin_result if invoke_result is None: invoke_result_list[tx_hash] = { code_key: message_code.Response.success } ScoreHelper().commit_tx_state() else: if code_key not in invoke_result: code_not_return = "Score not return code" if error_message_key in invoke_result: raise ScoreInvokeError( code_not_return + ": " + invoke_result[error_message_key]) raise ScoreInvokeError(code_not_return) elif invoke_result[ code_key] == message_code.Response.success: ScoreHelper().commit_tx_state() elif error_message_key in invoke_result: invoke_result_list[tx_hash][ error_message_key] = invoke_result[ error_message_key] ScoreHelper().reset_tx_state() invoke_result_list[tx_hash][ code_key] = invoke_result[code_key] # if score raise exception result to fail and put error message except Exception as e: logging.exception( "tx %s score invoke is fail!! : %s ", str(tx_hash), e) ScoreHelper().reset_tx_state() invoke_result[code_key] = ScoreResponse.EXCEPTION invoke_result[error_message_key] = str(e) invoke_result_list[tx_hash] = invoke_result peer_id = transaction.meta[Transaction.PEER_ID_KEY] util.apm_event( self._score_service.peer_id, { 'event_type': 'ScoreInvoke', 'peer_id': self._score_service.peer_id, 'peer_name': conf.PEER_NAME, 'channel_name': self._score_service.channel_name, 'data': { 'request_peer_id': peer_id, 'tx_data': transaction.get_data_string(), 'invoke_result': invoke_result } }) try: self._score_service.iiss_plugin.after_invoke( invoke_result_list=invoke_result_list, block=block) except Exception as e: logging.error(f"IISS Plugin Exception({e})") util.exit_and_msg( f"Shutdown Peer by IISS Plugin Exception({e})") ScoreHelper().precommit_state() self.__temp_invoke_results[block.height][ block.block_hash] = invoke_result_list if block.confirmed_tx_len > 0: commit_state = ScoreHelper().get_block_commit_state( block.height, block.block_hash) else: commit_state = {} meta = json.dumps(invoke_result_list) return loopchain_pb2.Message( code=message_code.Response.success, meta=meta, object=pickle.dumps(commit_state))
class UserScore(ScoreBase): """ICX Coin Score code ICX SCORE Prototyping code to explain basic SCORE example, NOT OFFICIAL ICX CODE!!!! NO GUARANTEE FOR ANY RISK OR TROUBLE. """ __score_info = None __db_id = 'icx.db' __db = None __score_helper = None __initialized = False def __init__(self, info=None): """Initialize SCORE. """ # Initialize SCORE info and DB module. self.logi('__init__() start') self.__init_score_info(info) self.__init_score_helper() self.__init_db() self.logd('__init__() end') def __init_score_info(self, info): """ Read package.json file as SCORE package information. ScoreHelper is special module to capsulize SCORE operation. """ if info is None: with open(dirname(__file__) + '/' + ScoreBase.PACKAGE_FILE, 'r') as f: self.__score_info = json.loads(f.read()) f.close() else: self.__score_info = info def __init_score_helper(self): """ Initialize ScoreHelper(). ScoreHelper is special module to capsulize SCORE operation. """ if self.__score_helper is None: self.__score_helper = ScoreHelper() def __init_db(self): """ Initialize database for SCORE. SCORE have to store all data into its own database. """ self.logd('__init_db() start') if self.__db is None: db = self.__score_helper.load_database( score_id=self.__db_id, database_type=ScoreDatabaseType.leveldb) self.logd(f'db({db}) is created.') self.__db = db # TESTING purpose. # Create virtual bank account ( 0x00000000000000000000000000000000000000000000 ) into 10^22 ICX. address = '0x' + '0' * 40 value = get_balance(self.__db, address) if value == 0: value = 10**22 set_balance(self.__db, address, value) self.logd(f'address({address}): {value}') self.logd('__init_db() end') def invoke(self, transaction, block): """ Handler of 'Invoke' requests. It's event handler of invoke request. You need to implement this handler like below. 0. Define the interface of functions in 'invoke' field of package.json. 1. Parse transaction data and get the name of function by reading 'method' field of transaction. 2. Call that function. :param transaction: transaction data. :param block: block data has transaction data. :return: response : Invoke result. """ self.logd('invoke() start') response = None try: if not verify_transaction(transaction): raise IcxError(Code.INVALID_TRANSACTION) # Parse transaction data. data = transaction.get_data_string() params = json.loads(data) self.logi(data) methods = { 'icx_init': self.__invoke_init, 'icx_sendTransaction': self.__invoke_sendTransaction } method_name = params['method'] method = methods.get(method_name, None) if method is None: raise IcxError(Code.METHOD_NOT_FOUND, method_name) # Call pre-defined functions in package.json by the request in transaction. method(transaction, block, params['params']) # Return response code. except IcxError as ie: response = create_invoke_response(ie.code, ie.message) except Exception as e: response = create_invoke_response(Code.UnknownError, str(e)) else: response = create_invoke_response(Code.OK) self.logi(f'invoke result: {str(response)}') self.logd('invoke() end') return response def __invoke_init(self, transaction, block, params): """ Initialize the value of account. :param transaction: Transaction data. :param block: Block data. :param params: params from transaction data including 'address' and'value'. """ self.logd('__invoke_init() start') self.logd(f'{str(params)}') if self.__initialized: raise IcxError(Code.INVALID_TRANSACTION, 'icx_score has been already initialized.') address = params['address'] value = params['value'] set_balance_str(self.__db, address, value) self.__initialized = True self.logd('__invoke_init() end') def __invoke_sendTransaction(self, transaction, block, params): """ Transfer money to other's bank account. :param transaction: Transaction data. :param block: Block data. :param params: params from transaction data including 'from', 'to', and 'value' """ self.logd('__invoke_sendTransaction() start') from_address = params['from'] to_address = params['to'] value = str_to_int(params['value']) if value <= 0: raise IcxError(Code.INVALID_PARAMS, f'value({value}) is invalid.') from_balance = get_balance(self.__db, from_address) if from_balance < value: raise IcxError( Code.INVALID_PARAMS, f'from_balance({from_balance}) is less than transaction value({value})' ) to_balance = get_balance(self.__db, to_address) from_balance -= value to_balance += value set_balances(self.__db, { from_address: from_balance, to_address: to_balance }) self.logd('__invoke_sendTransaction() end') def query(self, params): """ Handler of 'Query' requests. It's event handler of query request. You need to implement this handler like below. 0. Define the interface of functions in 'query' field of package.json. 1. Parse transaction data and get the name of function by reading 'method' field of transaction. 2. Call that function. :param transaction: transaction data. :param block: block data has transaction data. :return: response : Query result. """ self.logd('query() start') self.logd('params: ' + str(params)) _id = None response = None methods = {'icx_getBalance': self.__query_getBalance} try: request = json.loads(params) _id = request['id'] method_name = request['method'] response = methods.get(method_name, self.__handle_method_not_found)(_id, request) except IcxError as ie: response = create_jsonrpc_error_response(_id, ie.code, ie.message) except Exception as e: response = create_jsonrpc_error_response(_id, Code.UnknownError) self.logd('query() end') return json.dumps(response) def __query_getBalance(self, _id, request): """ Get the current value of bank account. :param _id: ID of request. Used it to distingush request. :param request: Request information :return: """ self.logd('__query_getBalance() start') self.logd(f'{str(request)}') params = request['params'] self.logd(params) address = params[0] self.logd(address) if not check_address(address): return create_jsonrpc_error_response( _id, Code.INVALID_PARAMS, f'invalid address({address})') value = get_balance_str(self.__db, address) response = create_jsonrpc_success_response(_id, value) self.logd('__query_get_balance() end') return response def __handle_method_not_found(self, _id, request): self.logd('__handle_method_not_found() start') method_name = request['method'] response = create_jsonrpc_error_response(_id, Code.METHOD_NOT_FOUND, method_name) self.logd('__handle_method_not_found() end') return response def info(self): return self.__score_info def log(self, level, message): if self.__score_helper: self.__score_helper.log("ICX", message, level) def logd(self, message): self.log(LogLevel.DEBUG, message) def logi(self, message): self.log(LogLevel.INFO, message)
def __init__(self, db_name): helper = ScoreHelper() self.db = helper.load_database(score_id=db_name, database_type=ScoreDatabaseType.leveldb)
def peer_id(self, value): self.__peer_id = ScoreHelper().peer_id = value
def __init__(self): # User can use several DB instances. self.__db = ScoreHelperDatabase("MY_OWN_DB", ScoreHelper()) self.__db_contract = ScoreHelperDatabase("Contract", ScoreHelper()) self.__db_Person = ScoreHelperDatabase("Person", ScoreHelper())