def test_send_tx_response(self): question = "234234" answer = "0x234234" result = convert_params(question, ParamType.send_tx_response) logging.info(f"result : {json.dumps(result, indent=4)}") self.assertEqual(result, answer) question = "0x234234" answer = "0x234234" result = convert_params(question, ParamType.send_tx_response) logging.info(f"result : {json.dumps(result, indent=4)}") self.assertEqual(result, answer) question = 234234 answer = "0x392fa" result = convert_params(question, ParamType.send_tx_response) logging.info(f"result : {json.dumps(result, indent=4)}") self.assertEqual(result, answer) question = "qsaad" answer = ValueError try: convert_params(question, ParamType.send_tx_response) except BaseException as e: self.assertEqual(answer, type(e))
async def icx_getTransactionResult(**kwargs): request = convert_params(kwargs, ParamType.get_tx_request) channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL channel_stub = StubCollection().channel_stubs[channel_name] verify_result = dict() tx_hash = request["txHash"] response_code, result = await channel_stub.async_task().get_invoke_result(tx_hash) if response_code == message_code.Response.fail_tx_not_invoked: raise GenericJsonRpcServerError( code=JsonError.INVALID_PARAMS, message=message_code.responseCodeMap[response_code][1], http_status=status.HTTP_BAD_REQUEST ) elif response_code == message_code.Response.fail_invalid_key_error or \ response_code == message_code.Response.fail: raise GenericJsonRpcServerError( code=JsonError.INVALID_PARAMS, message='Invalid params txHash', http_status=status.HTTP_BAD_REQUEST ) if result: try: result_dict = json.loads(result) verify_result = result_dict except json.JSONDecodeError as e: logging.warning(f"your result is not json, result({result}), {e}") response = convert_params(verify_result, ParamType.get_tx_result_response) return response
def score_write_precommit_state(self, block: Block): logging.debug( f"call score commit {ChannelProperty().name} {block.height} {block.block_hash}" ) if conf.USE_EXTERNAL_SCORE: request = { "blockHeight": block.height, "blockHash": block.block_hash, } request = convert_params(request, ParamType.write_precommit_state) stub = StubCollection().icon_score_stubs[ChannelProperty().name] stub.sync_task().write_precommit_state(request) return True else: block_commit_info = json.dumps({ "block_height": block.height, "block_hash": block.block_hash }) stub = StubCollection().score_stubs[ChannelProperty().name] response = stub.sync_task().write_precommit_state( block_commit_info) if response.code == message_code.Response.success: return True else: logging.error(f"score db commit fail cause {response.message}") return False
def score_invoke(self, _block: Block) -> dict or None: if conf.USE_EXTERNAL_SCORE: method = "icx_sendTransaction" transactions = [] for tx in _block.confirmed_transaction_list: data = tx.icx_origin_data transaction = {"method": method, "params": data} transactions.append(transaction) request = { 'block': { 'blockHeight': _block.height, 'blockHash': _block.block_hash, 'prevBlockHash': _block.prev_block_hash, 'timestamp': _block.time_stamp }, 'transactions': transactions } request = convert_params(request, ParamType.invoke) stub = StubCollection().icon_score_stubs[ChannelProperty().name] response = stub.sync_task().invoke(request) response_to_json_query(response) _block.commit_state[ ChannelProperty().name] = response['stateRootHash'] return response["txResults"] else: stub = StubCollection().score_stubs[ChannelProperty().name] response = stub.sync_task().score_invoke(_block) if response.code == message_code.Response.success: commit_state = pickle.loads(response.object) _block.commit_state = commit_state return json.loads(response.meta) return None
def score_write_precommit_state(self, block: Block): logging.debug( f"call score commit {ChannelProperty().name} {block.header.height} {block.header.hash.hex()}" ) new_block_hash = block.header.hash try: old_block_hash = self.__block_manager.get_old_block_hash( block.header.height, new_block_hash) except KeyError: old_block_hash = new_block_hash logging.debug(f"Block Hash : {old_block_hash} -> {new_block_hash}") request = { "blockHeight": block.header.height, "oldBlockHash": old_block_hash.hex(), "newBlockHash": new_block_hash.hex() } request = convert_params(request, ParamType.write_precommit_state) stub = StubCollection().icon_score_stubs[ChannelProperty().name] precommit_result: dict = stub.sync_task().write_precommit_state( request) if "error" in precommit_result: raise WritePrecommitStateError(precommit_result['error']) self.__block_manager.pop_old_block_hashes(block.header.height) return True
def genesis_invoke(self, block: Block) -> ('Block', dict): method = "icx_sendTransaction" transactions = [] for tx in block.body.transactions.values(): hash_version = conf.CHANNEL_OPTION[ ChannelProperty().name]["genesis_tx_hash_version"] tx_serializer = TransactionSerializer.new(tx.version, hash_version) transaction = { "method": method, "params": { "txHash": tx.hash.hex() }, "genesisData": tx_serializer.to_full_data(tx) } transactions.append(transaction) request = { 'block': { 'blockHeight': block.header.height, 'blockHash': block.header.hash.hex(), 'timestamp': block.header.timestamp }, 'transactions': transactions } request = convert_params(request, ParamType.invoke) stub = StubCollection().icon_score_stubs[ChannelProperty().name] response = stub.sync_task().invoke(request) response_to_json_query(response) block_builder = BlockBuilder.from_new(block) block_builder.commit_state = { ChannelProperty().name: response['stateRootHash'] } new_block = block_builder.build() return new_block, response["txResults"]
def __request_roll_back(self): target_block = self.blockchain.find_block_by_hash32( self.blockchain.last_block.header.prev_hash) if not self.blockchain.check_rollback_possible(target_block): util.logger.warning( f"The request cannot be rolled back to the target block({target_block})." ) return request_origin = { 'blockHeight': target_block.header.height, 'blockHash': target_block.header.hash.hex_0x() } request = convert_params(request_origin, ParamType.roll_back) stub = StubCollection().icon_score_stubs[ChannelProperty().name] util.logger.debug(f"Rollback request({request})") response: dict = cast(dict, stub.sync_task().rollback(request)) response_to_json_query(response) result_height = response.get("blockHeight") if hex(target_block.header.height) == result_height: util.logger.info(f"Rollback Success") self.blockchain.roll_back(target_block) self.rebuild_block() else: util.logger.warning(f"{response}")
def request_rollback(self) -> bool: """Request block data rollback behind to 1 block :return: if rollback success return True, else return False """ target_block = self.blockchain.find_block_by_hash32(self.blockchain.last_block.header.prev_hash) if not self.blockchain.check_rollback_possible(target_block): util.logger.warning(f"The request cannot be rollback to the target block({target_block}).") return False request_origin = { 'blockHeight': target_block.header.height, 'blockHash': target_block.header.hash.hex_0x() } request = convert_params(request_origin, ParamType.roll_back) stub = StubCollection().icon_score_stubs[ChannelProperty().name] util.logger.debug(f"Rollback request({request})") response: dict = cast(dict, stub.sync_task().rollback(request)) try: response_to_json_query(response) except GenericJsonRpcServerError as e: util.logger.warning(f"response error = {e}") else: result_height = response.get("blockHeight") if hex(target_block.header.height) == result_height: util.logger.info(f"Rollback Success. result height = {result_height}") self.blockchain.rollback(target_block) self.rebuild_block() return True util.logger.warning(f"Rollback Fail. response = {response}") return False
async def icx_getLastBlock(**kwargs): block_hash, result = await get_block_by_params(block_height=-1) util.logger.spam(f"JSONRPC_v3:icx_getLastBlock::block_hash({block_hash})") response = convert_params(result['block'], ParamType.get_block_response) return response
def score_invoke(self, _block: Block) -> dict or None: method = "icx_sendTransaction" transactions = [] for tx in _block.body.transactions.values(): tx_serializer = TransactionSerializer.new(tx.version, self.block_manager.get_blockchain().tx_versioner) transaction = { "method": method, "params": tx_serializer.to_full_data(tx) } transactions.append(transaction) request = { 'block': { 'blockHeight': _block.header.height, 'blockHash': _block.header.hash.hex(), 'prevBlockHash': _block.header.prev_hash.hex() if _block.header.prev_hash else '', 'timestamp': _block.header.timestamp }, 'transactions': transactions } request = convert_params(request, ParamType.invoke) stub = StubCollection().icon_score_stubs[ChannelProperty().name] response = stub.sync_task().invoke(request) response_to_json_query(response) block_builder = BlockBuilder.from_new(_block, self.__block_manager.get_blockchain().tx_versioner) block_builder.commit_state = { ChannelProperty().name: response['stateRootHash'] } new_block = block_builder.build() return new_block, response["txResults"]
async def icx_sendTransaction(**kwargs): if RestProperty().node_type == conf.NodeType.CitizenNode: return await redirect_request_to_rs( kwargs, RestProperty().rs_target) request = make_request("icx_sendTransaction", kwargs) icon_stub = StubCollection().icon_score_stubs[conf.LOOPCHAIN_DEFAULT_CHANNEL] response = await icon_stub.async_task().validate_transaction(request) response_to_json_query(response) channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL channel_stub = StubCollection().channel_stubs[channel_name] response_code, tx_hash = \ await channel_stub.async_task().create_icx_tx(kwargs) if response_code != message_code.Response.success: raise GenericJsonRpcServerError( code=JsonError.INVALID_REQUEST, message=message_code.responseCodeMap[response_code][1], http_status=status.HTTP_BAD_REQUEST ) if tx_hash is None: raise GenericJsonRpcServerError( code=JsonError.INVALID_REQUEST, message='txHash is None', http_status=status.HTTP_BAD_REQUEST ) return convert_params(tx_hash, ParamType.send_tx_response)
async def icx_getBlockByHeight(**kwargs): request = convert_params(kwargs, ParamType.get_block_by_height_request) block_hash, result = await get_block_by_params(block_height=request['height']) util.logger.spam(f"JSONRPC_v3:icx_getBlockByHeight::block_hash({block_hash})") response_code = result['response_code'] if response_code != message_code.Response.success: raise GenericJsonRpcServerError( code=JsonError.INVALID_PARAMS, message=message_code.responseCodeMap[response_code][1], http_status=status.HTTP_BAD_REQUEST ) response = convert_params(result['block'], ParamType.get_block_response) return response
async def icx_getTransactionByHash(**kwargs): request = convert_params(kwargs, ParamType.get_tx_request) channel_name = conf.LOOPCHAIN_DEFAULT_CHANNEL channel_stub = StubCollection().channel_stubs[channel_name] response_code, tx_info = await channel_stub.async_task().get_tx_info(request["txHash"]) if response_code == message_code.Response.fail_invalid_key_error: raise GenericJsonRpcServerError( code=JsonError.INVALID_PARAMS, message='Invalid params txHash', http_status=status.HTTP_BAD_REQUEST ) result = tx_info["transaction"] result["txIndex"] = tx_info["tx_index"] result["blockHeight"] = tx_info["block_height"] result["blockHash"] = tx_info["block_hash"] response = convert_params(result, ParamType.get_tx_by_hash_response) return response
def score_write_precommit_state(self, block: Block): logging.debug(f"call score commit {ChannelProperty().name} {block.header.height} {block.header.hash.hex()}") request = { "blockHeight": block.header.height, "blockHash": block.header.hash.hex(), } request = convert_params(request, ParamType.write_precommit_state) stub = StubCollection().icon_score_stubs[ChannelProperty().name] stub.sync_task().write_precommit_state(request) return True
def test_get_tx_by_hash_response(self): question = { "txHash": "00abcdef1234567890", "blockHeight": "1234", "blockHash": "00abcdef0981" } answer = { "txHash": "0x00abcdef1234567890", "blockHeight": "0x4d2", "blockHash": "0x00abcdef0981" } result = convert_params(question, ParamType.get_tx_by_hash_response) logging.info(f"result : {json.dumps(result, indent=4)}") self.assertEqual(result, answer)
def genesis_invoke(self, block: Block) -> ('Block', dict): method = "icx_sendTransaction" transactions = [] for tx in block.body.transactions.values(): tx_serializer = TransactionSerializer.new( tx.version, self.block_manager.get_blockchain().tx_versioner) transaction = { "method": method, "params": { "txHash": tx.hash.hex() }, "genesisData": tx_serializer.to_full_data(tx) } transactions.append(transaction) request = { 'block': { 'blockHeight': block.header.height, 'blockHash': block.header.hash.hex(), 'timestamp': block.header.timestamp }, 'transactions': transactions } request = convert_params(request, ParamType.invoke) stub = StubCollection().icon_score_stubs[ChannelProperty().name] response = stub.sync_task().invoke(request) response_to_json_query(response) tx_receipts = response["txResults"] block_builder = BlockBuilder.from_new( block, self.block_manager.get_blockchain().tx_versioner) block_builder.reset_cache() block_builder.peer_id = block.header.peer_id block_builder.signature = block.header.signature block_builder.commit_state = { ChannelProperty().name: response['stateRootHash'] } block_builder.state_hash = Hash32( bytes.fromhex(response['stateRootHash'])) block_builder.receipts = tx_receipts block_builder.reps = self.get_rep_ids() new_block = block_builder.build() return new_block, tx_receipts
def score_remove_precommit_state(self, block: Block): if not util.channel_use_icx(ChannelProperty().name): request = { "blockHeight": block.height, "blockHash": block.block_hash, } request = convert_params(request, ParamType.remove_precommit_state) stub = StubCollection().icon_score_stubs[ChannelProperty().name] stub.sync_task().remove_precommit_state(request) return True else: invoke_fail_info = json.dumps({"block_height": block.height, "block_hash": block.block_hash}) stub = StubCollection().score_stubs[ChannelProperty().name] stub.sync_task().remove_precommit_state(invoke_fail_info) return True
def genesis_invoke(self, block: Block) -> dict or None: if util.channel_use_icx(ChannelProperty().name): method = "icx_sendTransaction" transactions = [] for tx in block.confirmed_transaction_list: transaction = { "method": method, "params": { "txHash": tx.tx_hash }, "genesisData": tx.genesis_origin_data } transactions.append(transaction) request = { 'block': { 'blockHeight': block.height, 'blockHash': block.block_hash, 'timestamp': block.time_stamp }, 'transactions': transactions } request = convert_params(request, ParamType.invoke) stub = StubCollection().icon_score_stubs[ChannelProperty().name] response = stub.sync_task().invoke(request) response_to_json_query(response) block.commit_state[ChannelProperty().name] = response['stateRootHash'] return response["txResults"] else: block_object = pickle.dumps(block) stub = StubCollection().score_stubs[ChannelProperty().name] response = stub.sync_task().genesis_invoke(block_object) if response.code == message_code.Response.success: return json.loads(response.meta) return None
def test_invoke(self): question = { "block": { "block_height": 1000, "block_hash": "0xa7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", "time_stamp": "1234567890", "prevBlockHash": "0xb7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", }, "transactions": [{ "method": "icx_sendTransaction", "params": { "version": "0x3", "from": "hxbe258ceb872e08851f1f59694dac2558708ece11", "to": "hxb0776ee37f5b45bfaea8cff1d8232fbb6122ec32", "value": "100", "stepLimit": "12345", "timestamp": "5500598", "nonce": "7362", "signature": "VAia7YZ2Ji6igKWzjR2YsGa2m53nKPrfK7uXYW78QLE+ATehAVZPC40szvAiA6NEU5gCYB4c4qaQzqDh2ugcHgA=", "dataType": "call", "data": { "method": "transfer", "params": { "from": "hxbe258ceb872e08851f1f59694dac2558708ece11", "to": "hxf5aac6e693ec2cb5973d3f314334670b3f85ad14", "value": "56bc75e2d63100000" } } } }] } answer = { "block": { "blockHeight": "0x3e8", "blockHash": "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", "timestamp": "0x499602d2", "prevBlockHash": "b7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", }, "transactions": [{ "method": "icx_sendTransaction", "params": { "version": "0x3", "from": "hxbe258ceb872e08851f1f59694dac2558708ece11", "to": "hxb0776ee37f5b45bfaea8cff1d8232fbb6122ec32", "value": "0x100", "stepLimit": "0x3039", "timestamp": "0x53eeb6", "nonce": "0x1cc2", "signature": "VAia7YZ2Ji6igKWzjR2YsGa2m53nKPrfK7uXYW78QLE+ATehAVZPC40szvAiA6NEU5gCYB4c4qaQzqDh2ugcHgA=", "dataType": "call", "data": { "method": "transfer", "params": { "from": "hxbe258ceb872e08851f1f59694dac2558708ece11", "to": "hxf5aac6e693ec2cb5973d3f314334670b3f85ad14", "value": "56bc75e2d63100000" } } } }] } result = convert_params(question, ParamType.invoke) logging.info(f"result : {json.dumps(result, indent=4)}") self.assertEqual(result, answer)
def test_get_block_response(self): question = { "prev_block_hash": "0x012332abcde", "merkle_tree_root_hash": "0x01234abc96", "time_stamp": "0x1cc3169d2c", "block_hash": "0x01282384583bb", "height": 124, "confirmed_transaction_list": [ { "from": "hx120983102983", "to": "hx109238019238", "txHash": "0123213b1a" }, { "from": "hx12098310293", "to": "hx10923801928", "txHash": "0123213b1a" }, { "from": "hx12093102983", "to": "hx10923809238", "txHash": "0123213b1a" }, { "from": "hx1209831029823", "to": "hx1092380192382", "txHash": "0123213b1a" } ] } answer = { "prev_block_hash": "0x012332abcde", "merkle_tree_root_hash": "0x01234abc96", "time_stamp": "0x1cc3169d2c", "block_hash": "0x01282384583bb", "height": 124, "confirmed_transaction_list": [ { "from": "hx120983102983", "to": "hx109238019238", "txHash": "0x0123213b1a" }, { "from": "hx12098310293", "to": "hx10923801928", "txHash": "0x0123213b1a" }, { "from": "hx12093102983", "to": "hx10923809238", "txHash": "0x0123213b1a" }, { "from": "hx1209831029823", "to": "hx1092380192382", "txHash": "0x0123213b1a" } ] } result = convert_params(question, ParamType.get_block_response) logging.info(f"result : {json.dumps(result, indent=4)}") self.assertEqual(result, answer)
async def node_GetBlockByHeight(**kwargs): request = convert_params(kwargs, ParamType.get_block_by_height_request) block_hash, response = await get_block_by_params( block_height=request['height'], with_commit_state=True) return response