class RFAIEventConsumer(EventConsumer): def __init__(self, net_id, ws_provider, ipfs_url, ipfs_port): self._ipfs_util = IPFSUtil(ipfs_url, ipfs_port) self._blockchain_util = BlockChainUtil("WS_PROVIDER", ws_provider) self._net_id = net_id def on_event(self, event): pass def _get_rfai_contract(self): base_contract_path = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..', 'node_modules', 'singularitynet-rfai-contracts')) rfai_contract = self._blockchain_util.get_contract_instance( base_contract_path, "RFAI", self._net_id) return rfai_contract def _get_rfai_metadata_from_ipfs(self, ipfs_hash): return self._ipfs_util.read_file_from_ipfs(ipfs_hash) def _get_event_data(self, event): return eval(event['data']['json_str']) def _get_metadata_hash(self, metadata_uri): return metadata_uri.decode("utf-8") def _get_rfai_service_request_by_id(self, request_id): rfai_contract = self._get_rfai_contract() result = self._blockchain_util.call_contract_function( rfai_contract, "getServiceRequestById", request_id) return result
def __init__( self, ws_provider, repository=None, ): self._blockchain_util = BlockChainUtil("WS_PROVIDER", ws_provider) self._event_repository = EventRepository(repository)
def __init__(self, repo, net_id): self.net_id = net_id self.repo = repo self.obj_blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[NETWORK_ID]['http_provider']) self.obj_channel_transaction_history_dao = ChannelTransactionStatusDataAccessObject( repo=self.repo)
def __init__(self, repo): self.repo = repo self.boto_utils = BotoUtils(region_name=REGION_NAME) self.blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[NETWORK_ID]['http_provider']) self.utils = Utils() self.channel_dao = ChannelDAO(repo=self.repo) self.wallet_dao = WalletDAO(repo=self.repo)
def open_channel_by_third_party(self, order_id, sender, sender_private_key, group_id, amount, currency, recipient): obj_wallet_dao = WalletDAO(obj_repo=self.obj_repo) self.obj_blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[NETWORK_ID]['http_provider']) method_name = "openChannelByThirdParty" self.mpe_address = self.obj_blockchain_util.read_contract_address( net_id=NETWORK_ID, path=MPE_ADDR_PATH, key='address') current_block_no = self.obj_blockchain_util.get_current_block_no() # 1 block no is mined in 15 sec on average, setting expiration as 10 years expiration = current_block_no + (10 * 365 * 24 * 60 * 4) agi_tokens = self.__calculate_agi_tokens(amount=amount, currency=currency) group_id_in_hex = "0x" + base64.b64decode(group_id).hex() r, s, v, signature = self.__generate_signature_details( recipient=recipient, group_id=group_id_in_hex, agi_tokens=agi_tokens, expiration=expiration, message_nonce=current_block_no, signer_key=sender_private_key) positional_inputs = (sender, SIGNER_ADDRESS, recipient, group_id_in_hex, agi_tokens, expiration, current_block_no, v, r, s) transaction_object = self.obj_blockchain_util.create_transaction_object( *positional_inputs, method_name=method_name, address=EXECUTOR_WALLET_ADDRESS, contract_path=MPE_CNTRCT_PATH, contract_address_path=MPE_ADDR_PATH, net_id=NETWORK_ID) raw_transaction = self.obj_blockchain_util.sign_transaction_with_private_key( transaction_object=transaction_object, private_key=EXECUTOR_WALLET_KEY) transaction_hash = self.obj_blockchain_util.process_raw_transaction( raw_transaction=raw_transaction) print("openChannelByThirdParty::transaction_hash", transaction_hash) obj_wallet_dao.insert_channel_history( order_id=order_id, amount=amount, currency=currency, type=method_name, address=sender, signature=signature, request_parameters=str(positional_inputs), transaction_hash=transaction_hash, status=0) return { "transaction_hash": transaction_hash, "signature": signature, "agi_tokens": agi_tokens, "positional_inputs": positional_inputs, "type": method_name }
def __init__(self, obj_repo): self.repo = obj_repo self.obj_transaction_history_dao = TransactionHistoryDAO(self.repo) self.lambda_client = boto3.client('lambda', region_name=REGION_NAME) self.boto_client = BotoUtils(REGION_NAME) self.wallet_service = WalletService() self.obj_blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[NETWORK_ID]['http_provider'] ) self.utils = Utils()
def verify_current_block_number(self): signed_block_number = int( self.event['headers']['x-currentblocknumber']) blockchain_util = BlockChainUtil(provider_type="WS_PROVIDER", provider=self.networks[self.net_id]['ws_provider']) current_block_number = blockchain_util.get_current_block_no() print(f"current block {current_block_number}\n" f"signed clock number {signed_block_number}") if current_block_number > signed_block_number + self.BLOCK_LIMIT or current_block_number < signed_block_number - self.BLOCK_LIMIT: print("current_block_number is more than signed block limit %s", current_block_number) return False return True
def __init__(self, net_id): self.net_id = net_id self.lambda_client = boto3.client("lambda", region_name=REGION_NAME) self.obj_utils = Utils() self.obj_blockchain_utils = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[self.net_id]["http_provider"], ) self.mpe_address = self.obj_blockchain_utils.read_contract_address( net_id=self.net_id, path=MPE_ADDR_PATH, key="address") self.current_block_no = self.obj_blockchain_utils.get_current_block_no( )
def __init__(self, env_type): self.__env_type = env_type if env_type == EnvironmentType.MAIN.value: self.__network_id = NETWORK_ID self.__contract_path = REG_CNTRCT_PATH self.__executor_address = "" self.__contract_address_path = REG_ADDR_PATH self.__blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[self.__network_id]['http_provider']) else: raise MethodNotImplemented()
def create_and_register_wallet(self): self.obj_blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[NETWORK_ID]['http_provider']) address, private_key = self.obj_blockchain_util.create_account() obj_wallet = Wallet(address=address, private_key=private_key, type=GENERAL_WALLET_TYPE, status=0) registered = self.register_wallet(obj_wallet=obj_wallet) if registered: return obj_wallet.get_wallet() raise Exception("Unable to create and register wallet.")
class BlockchainEventProducer(EventProducer): def __init__( self, ws_provider, repository=None, ): self._blockchain_util = BlockChainUtil("WS_PROVIDER", ws_provider) self._event_repository = EventRepository(repository) def _get_base_contract_path(self): pass def _get_events_from_blockchain(self, start_block_number, end_block_number, net_id): base_contract_path = self._get_base_contract_path() contract = self._blockchain_util.get_contract_instance( base_contract_path, self._contract_name, net_id=net_id) contract_events = contract.events all_blockchain_events = [] for attributes in contract_events.abi: if attributes['type'] == 'event': event_name = attributes['name'] event_object = getattr(contract.events, event_name) blockchain_events = event_object.createFilter( fromBlock=start_block_number, toBlock=end_block_number).get_all_entries() all_blockchain_events.extend(blockchain_events) return all_blockchain_events def _produce_contract_events(self, start_block_number, end_block_number, net_id): events = self._get_events_from_blockchain(start_block_number, end_block_number, net_id) logger.info(f"read no of events {len(events)}") return events def _get_end_block_number(self, last_processed_block_number, batch_limit): current_block_number = self._blockchain_util.get_current_block_no() end_block_number = last_processed_block_number + batch_limit if current_block_number <= end_block_number: end_block_number = current_block_number return end_block_number def produce_event(self, net_id): pass
def setUp(self): self.net_id = 3 self.http_provider = Web3.HTTPProvider( NETWORKS[self.net_id]['http_provider']) self.obj_utils = BlockChainUtil(provider_type="HTTP_PROVIDER", provider=self.http_provider) self.mpe_address = self.obj_utils.read_contract_address( net_id=self.net_id, path=MPE_ADDR_PATH, key='address') self.recipient = "0x9c302750c50307D3Ad88eaA9a6506874a15cE4Cb" self.group_id = "0x" + base64.b64decode( "DS2OoKSfGE/7hAO/023psl4Qdj0MJvYsreJbCoAHVSc=").hex() self.agi_tokens = 1 self.current_block_no = self.obj_utils.get_current_block_no() self.expiration = self.current_block_no + 10000000 self.channel_id = 0
class MPEEventConsumer(EventConsumer): _mpe_repository = MPERepository(Repository(NETWORK_ID, NETWORKS=NETWORKS)) def __init__(self, ws_provider): self.blockchain_util = BlockChainUtil("WS_PROVIDER", ws_provider) def on_event(self, event): net_id = NETWORK_ID base_contract_path = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..', 'node_modules', 'singularitynet-platform-contracts')) mpe_contract = self.blockchain_util.get_contract_instance( base_contract_path, "MPE", net_id) logger.info(f"processing mpe event {event}") event_name = event["name"] event_data = event["data"] mpe_data = eval(event_data['json_str']) channel_id = int(mpe_data['channelId']) if event_name == 'ChannelOpen': self._mpe_repository.create_channel(mpe_data) else: channel_data = mpe_contract.functions.channels(channel_id).call() group_id = base64.b64encode(channel_data[4]).decode('utf8') self._mpe_repository.update_channel(channel_id=channel_id, group_id=group_id, channel_data=channel_data)
class ServiceEventConsumer(EventConsumer): _connection = Repository(NETWORK_ID, NETWORKS=NETWORKS) _service_repository = ServiceRepository(_connection) def __init__(self, ws_provider, ipfs_url, ipfs_port): self._blockchain_util = BlockChainUtil("WS_PROVIDER", ws_provider) self._s3_util = S3Util(S3_BUCKET_ACCESS_KEY, S3_BUCKET_SECRET_KEY) self._ipfs_util = IPFSUtil(ipfs_url, ipfs_port) def on_event(self, event): pass def _fetch_tags(self, registry_contract, org_id_hex, service_id_hex): tags_data = registry_contract.functions.getServiceRegistrationById( org_id_hex, service_id_hex).call() return tags_data def _get_org_id_from_event(self, event): event_data = event['data'] service_data = eval(event_data['json_str']) org_id_bytes = service_data['orgId'] org_id = Web3.toText(org_id_bytes).rstrip("\x00") return org_id def _get_service_id_from_event(self, event): event_data = event['data'] service_data = eval(event_data['json_str']) service_id_bytes = service_data['serviceId'] service_id = Web3.toText(service_id_bytes).rstrip("\x00") return service_id def _get_metadata_uri_from_event(self, event): event_data = event['data'] service_data = eval(event_data['json_str']) metadata_uri = Web3.toText( service_data['metadataURI'])[7:].rstrip("\u0000") return metadata_uri def _get_registry_contract(self): net_id = NETWORK_ID base_contract_path = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..', 'node_modules', 'singularitynet-platform-contracts')) registry_contract = self._blockchain_util.get_contract_instance( base_contract_path, "REGISTRY", net_id) return registry_contract def _get_service_details_from_blockchain(self, event): logger.info(f"processing service event {event}") registry_contract = self._get_registry_contract() org_id = self._get_org_id_from_event(event) service_id = self._get_service_id_from_event(event) tags_data = self._fetch_tags(registry_contract=registry_contract, org_id_hex=org_id.encode("utf-8"), service_id_hex=service_id.encode("utf-8")) return org_id, service_id, tags_data
class ChannelTransactionStatusService: def __init__(self, repo, net_id): self.net_id = net_id self.repo = repo self.obj_blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[NETWORK_ID]['http_provider']) self.obj_channel_transaction_history_dao = ChannelTransactionStatusDataAccessObject( repo=self.repo) def manage_channel_transaction_status(self): transaction_data = self.obj_channel_transaction_history_dao.get_pending_transaction_data( ) print(transaction_data) for transaction_record in transaction_data: transaction_hash = transaction_record['transaction_hash'] transaction_receipt = self.obj_blockchain_util.get_transaction_receipt_from_blockchain( transaction_hash=transaction_hash) if transaction_receipt is not None: status = TransactionStatus.SUCCESS if transaction_receipt.status == 1 else TransactionStatus.FAILED self.obj_channel_transaction_history_dao.update_channel_transaction_history( transaction_hash=transaction_hash, status=status)
class OrderService: def __init__(self, obj_repo): self.repo = obj_repo self.obj_transaction_history_dao = TransactionHistoryDAO(self.repo) self.lambda_client = boto3.client('lambda', region_name=REGION_NAME) self.boto_client = BotoUtils(REGION_NAME) self.wallet_service = WalletService() self.obj_blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[NETWORK_ID]['http_provider'] ) self.utils = Utils() def initiate_order(self, username, payload_dict): """ Initiate Order Step 1 Order Creation Step 2 Initiate Payment Step 3 Persist Transaction History """ price = payload_dict["price"] order_type = payload_dict["item_details"]["order_type"] item_details = payload_dict["item_details"] group_id = item_details["group_id"] org_id = item_details["org_id"] channel_id = "" amount_in_cogs = self.calculate_amount_in_cogs(amount=price["amount"], currency=price["currency"]) if amount_in_cogs < 1: raise Exception("Amount in cogs should be greater than equal to 1") item_details["amount_in_cogs"] = amount_in_cogs if order_type == OrderType.CREATE_WALLET_AND_CHANNEL.value: item_details["wallet_address"] = "" recipient = self.get_payment_address_for_org(group_id=group_id, org_id=org_id) elif order_type == OrderType.CREATE_CHANNEL.value: recipient = self.get_payment_address_for_org(group_id=group_id, org_id=org_id) elif order_type == OrderType.FUND_CHANNEL.value: channel = self.get_channel_for_topup(username=username, group_id=group_id, org_id=org_id) if channel is None: raise Exception(f"Channel not found for the user: {username} with org: {org_id} group: {group_id}") recipient = channel["recipient"] channel_id = channel["channel_id"] item_details["wallet_address"] = channel["address"] else: raise Exception("Invalid order type") item_details["channel_id"] = channel_id item_details["recipient"] = recipient order_details = self.manage_create_order( username=username, item_details=item_details, price=price ) order_id = order_details["order_id"] try: payment_data = self.manage_initiate_payment( username=username, order_id=order_id, price=price, payment_method=payload_dict["payment_method"] ) payment_id = payment_data["payment_id"] raw_payment_data = json.dumps(payment_data["payment"]) obj_transaction_history = TransactionHistory( username=username, order_id=order_id, order_type=order_type, payment_id=payment_id, raw_payment_data=raw_payment_data, status=Status.PAYMENT_INITIATED.value ) self.obj_transaction_history_dao.insert_transaction_history(obj_transaction_history=obj_transaction_history) return payment_data except Exception as e: obj_transaction_history = TransactionHistory( username=username, order_id=order_id, order_type=order_type, status=Status.PAYMENT_INITIATION_FAILED.value ) self.obj_transaction_history_dao.insert_transaction_history(obj_transaction_history=obj_transaction_history) print(repr(e)) raise e def get_channel_for_topup(self, username, group_id, org_id): channel_details = self.wallet_service.get_channel_details( username=username, group_id=group_id, org_id=org_id ) wallets = channel_details["wallets"] for wallet in wallets: if (wallet["type"] == "GENERAL") and len(wallet["channels"]) > 0: if wallet["channels"][0]["signer"] == SIGNER_ADDRESS: wallet_address = wallet["address"] channel = wallet["channels"][0] channel["address"] = wallet_address return channel return None def get_payment_address_for_org(self, org_id, group_id): group_details_event = { "path": f"/org/{org_id}/group/{quote(group_id, safe='')}", "pathParameters": { "orgId": org_id, "group_id": quote(group_id, safe='') }, "httpMethod": "GET" } logger.info(f"get_group_for_org request: {org_id} and {group_id}") group_details_lambda_response = self.lambda_client.invoke( FunctionName=GET_GROUP_FOR_ORG_API_ARN, InvocationType='RequestResponse', Payload=json.dumps(group_details_event) ) group_details_response = json.loads(group_details_lambda_response.get('Payload').read()) logger.info(f"get_group_for_org response: {group_details_response}") if group_details_response["statusCode"] != 200: raise Exception(f"Failed to fetch group details for org_id:{org_id} " f"group_id {group_id}") group_details_response_body = json.loads(group_details_response["body"]) groups = group_details_response_body["data"]["groups"] if len(groups) == 0: raise Exception(f"Failed to find group {group_id} for org_id: {org_id}") return groups[0]["payment"]["payment_address"] def calculate_amount_in_cogs(self, amount, currency): if currency == "USD": amount_in_cogs = round(amount * USD_TO_COGS_CONVERSION_FACTOR) return amount_in_cogs else: raise Exception("Currency %s not supported.", currency) def execute_order(self, username, payload_dict): """ Execute Order Step 1 Execute Payment Step 2 Get Receipient Address Step 3 Process Order Step 4 Update Transaction History """ order_id = payload_dict["order_id"] payment_id = payload_dict["payment_id"] order = self.get_order_details_by_order_id(order_id, username) payment = None for payment_item in order["payments"]: if payment_item["payment_id"] == payment_id: payment = payment_item break if payment is None: raise Exception(f"Failed to fetch order details for order_id {order_id} \n" f"payment_id {payment_id} \n" f"username{username}") order_type = order["item_details"]["order_type"] item_details = order["item_details"] payment_method = payment["payment_details"]["payment_method"] paid_payment_details = payload_dict["payment_details"] price = payment["price"] status = Status.PAYMENT_EXECUTION_FAILED.value self.manage_execute_payment( username=username, order_id=order_id, payment_id=payment_id, payment_details=paid_payment_details, payment_method=payment_method ) status = Status.PAYMENT_EXECUTED.value try: status = Status.ORDER_PROCESSING_FAILED.value amount_in_cogs = self.calculate_amount_in_cogs(amount=price["amount"], currency=price["currency"]) if amount_in_cogs < 1: raise Exception("Amount in cogs should be greater than equal to 1") processed_order_data = self.manage_process_order( username=username, order_id=order_id, order_type=order_type, amount=price["amount"], currency=price["currency"], order_data=item_details, amount_in_cogs=amount_in_cogs ) status = Status.ORDER_PROCESSED.value obj_transaction_history = TransactionHistory( username=username, order_id=order_id, order_type=order_type, status=status, payment_id=payment_id, payment_method=payment_method, raw_payment_data=json.dumps(paid_payment_details) ) self.obj_transaction_history_dao.insert_transaction_history(obj_transaction_history=obj_transaction_history) processed_order_data["price"] = price processed_order_data["item_details"] = item_details return processed_order_data except Exception as e: obj_transaction_history = TransactionHistory( username=username, order_id=order_id, order_type=order_type, status=status ) self.obj_transaction_history_dao.insert_transaction_history(obj_transaction_history=obj_transaction_history) print(repr(e)) raise e def get_order_details_by_order_id(self, order_id, username): order_details_event = { "path": f"order/{order_id}", "pathParameters": {"order_id": order_id}, "httpMethod": "GET" } logger.info(f"Requesting order details for order_id {order_id}") response = self.lambda_client.invoke( FunctionName=ORDER_DETAILS_ORDER_ID_ARN, InvocationType='RequestResponse', Payload=json.dumps(order_details_event) ) order_details_response = json.loads(response.get('Payload').read()) if order_details_response["statusCode"] != 200: raise Exception(f"Failed to fetch order details for order_id {order_id} username{username}") order_details_data = json.loads(order_details_response["body"]) if order_details_data["username"] != username: raise Exception(f"Failed to fetch order details for order_id {order_id} username{username}") return order_details_data def manage_initiate_payment(self, username, order_id, price, payment_method): initiate_payment_event = { "pathParameters": {"order_id": order_id}, "httpMethod": "POST", "body": json.dumps({"price": price, "payment_method": payment_method}) } response = self.lambda_client.invoke( FunctionName=INITIATE_PAYMENT_SERVICE_ARN, InvocationType='RequestResponse', Payload=json.dumps(initiate_payment_event) ) initiate_payment_data = json.loads(response.get('Payload').read()) if initiate_payment_data["statusCode"] == 201: return json.loads(initiate_payment_data["body"]) else: logger.error("Error initiating payment for user %s", username) raise PaymentInitiateFailed def manage_create_order(self, username, item_details, price): create_order_event = { "path": "/order/create", "httpMethod": "POST", "body": json.dumps({"price": price, "item_details": item_details, "username": username}) } create_order_service_response = self.boto_client.invoke_lambda( lambda_function_arn=CREATE_ORDER_SERVICE_ARN, invocation_type='RequestResponse', payload=json.dumps(create_order_event) ) logger.info(f"create_order_service_response: {create_order_service_response}") if create_order_service_response["statusCode"] == 201: return json.loads(create_order_service_response["body"]) else: raise Exception(f"Error creating order for user {username}") def manage_execute_payment(self, username, order_id, payment_id, payment_details, payment_method): execute_payment_event = { "pathParameters": {"order_id": order_id, "payment_id": payment_id}, "body": json.dumps({"payment_method": payment_method, "payment_details": payment_details}) } response = self.lambda_client.invoke( FunctionName=EXECUTE_PAYMENT_SERVICE_ARN, InvocationType='RequestResponse', Payload=json.dumps(execute_payment_event) ) payment_executed = json.loads(response.get('Payload').read()) if payment_executed["statusCode"] == 201: return payment_executed else: raise Exception(f"Error executing payment for username {username} against order_id {order_id}") def manage_process_order(self, username, order_id, order_type, amount, currency, order_data, amount_in_cogs): logger.info(f"Order Data {order_data}") group_id = order_data["group_id"] org_id = order_data["org_id"] recipient = order_data["recipient"] channel_id = order_data["channel_id"] sender = order_data["wallet_address"] if order_type == OrderType.CREATE_WALLET_AND_CHANNEL.value: wallet_create_payload = { "path": "/wallet", "body": json.dumps({"username": username}), "httpMethod": "POST" } wallet_create_lambda_response = self.lambda_client.invoke( FunctionName=WALLETS_SERVICE_ARN, InvocationType='RequestResponse', Payload=json.dumps(wallet_create_payload) ) wallet_create_response = json.loads(wallet_create_lambda_response.get("Payload").read()) if wallet_create_response["statusCode"] != 200: raise Exception("Failed to create wallet") wallet_create_response_body = json.loads(wallet_create_response["body"]) wallet_details = wallet_create_response_body["data"] try: current_block_no = self.obj_blockchain_util.get_current_block_no() # 1 block no is mined in 15 sec on average, setting expiration as 10 years expiration = current_block_no + (10 * 365 * 24 * 60 * 4) message_nonce = current_block_no self.EXECUTOR_WALLET_ADDRESS = self.boto_client.get_ssm_parameter(EXECUTOR_ADDRESS) group_id_in_hex = "0x" + base64.b64decode(group_id).hex() signature_details = self.generate_signature_for_open_channel_for_third_party( recipient=recipient, group_id=group_id_in_hex, amount_in_cogs=amount_in_cogs, expiration=expiration, message_nonce=message_nonce, sender_private_key=wallet_details["private_key"], executor_wallet_address=self.EXECUTOR_WALLET_ADDRESS ) logger.info(f"Signature Details {signature_details}") open_channel_body = { 'order_id': order_id, 'sender': wallet_details["address"], 'signature': signature_details["signature"], 'r': signature_details["r"], 's': signature_details["s"], 'v': signature_details["v"], 'group_id': group_id, 'org_id': org_id, 'amount': amount, 'currency': currency, 'recipient': recipient, 'current_block_no': current_block_no, 'amount_in_cogs': amount_in_cogs } channel_details = self.wallet_service.create_channel(open_channel_body=open_channel_body) channel_details.update(wallet_details) return channel_details except Exception as e: logger.error("Failed to create channel") logger.error(repr(e)) response = { "transaction_hash": "", "signature": "", "amount_in_cogs": 0, "price": { "amount": amount, "currency": currency }, "item_details": order_data } response.update(wallet_details) raise ChannelCreationFailed("Failed to create channel", wallet_details=response) elif order_type == OrderType.CREATE_CHANNEL.value: try: logger.info(f"Order Data {order_data}") signature = order_data["signature"] v, r, s = Web3.toInt(hexstr="0x" + signature[-2:]), signature[:66], "0x" + signature[66:130] open_channel_body = { 'order_id': order_id, 'sender': order_data["wallet_address"], 'signature': order_data["signature"], 'r': r, 's': s, 'v': v, 'group_id': group_id, 'org_id': org_id, 'amount': amount, 'currency': currency, 'recipient': recipient, 'current_block_no': order_data["current_block_number"], 'amount_in_cogs': amount_in_cogs } channel_details = self.wallet_service.create_channel(open_channel_body=open_channel_body) logger.info("channel_details: ", channel_details) return channel_details except Exception as e: logger.error("Failed to create channel") logger.error(repr(e)) raise ChannelCreationFailed("Failed to create channel", wallet_details=order_data) elif order_type == OrderType.FUND_CHANNEL.value: try: fund_channel_body = { 'order_id': order_id, 'group_id': group_id, 'org_id': org_id, 'amount': amount, 'channel_id': channel_id, 'currency': currency, 'recipient': recipient, 'sender': sender, 'amount_in_cogs': amount_in_cogs } fund_channel_payload = { "path": "/wallet/channel/deposit", "body": json.dumps(fund_channel_body), "httpMethod": "POST" } fund_channel_lambda_response = self.lambda_client.invoke( FunctionName=WALLETS_SERVICE_ARN, InvocationType='RequestResponse', Payload=json.dumps(fund_channel_payload) ) fund_channel_response = json.loads(fund_channel_lambda_response.get("Payload").read()) if fund_channel_response["statusCode"] != 200: raise Exception(f"Failed to add funds in channel for {fund_channel_body}") fund_channel_response_body = json.loads(fund_channel_response["body"]) fund_channel_transaction_details = fund_channel_response_body["data"] return fund_channel_transaction_details except Exception as e: logger.error("Failed to fund channel") logger.error(repr(e)) raise FundChannelFailed() else: raise Exception("Order type is not valid.") def get_order_details_by_username(self, username): order_details_event = { "path": f"/order", "queryStringParameters": {"username": username}, "httpMethod": "GET" } logger.info(f"Requesting order details for username {username}") order_details_response = self.boto_client.invoke_lambda( lambda_function_arn=ORDER_DETAILS_BY_USERNAME_ARN, invocation_type='RequestResponse', payload=json.dumps(order_details_event) ) if order_details_response["statusCode"] != 200: raise Exception(f"Failed to fetch order details for username{username}") org_id_name_mapping = self.get_organizations_from_contract() order_details_response_body = json.loads(order_details_response["body"]) orders = order_details_response_body["orders"] for order in orders: order_id = order["order_id"] order["wallet_type"] = "GENERAL" if "org_id" in order["item_details"]: org_id = order["item_details"]["org_id"] if org_id in org_id_name_mapping: order["item_details"]["organization_name"] = org_id_name_mapping[org_id] transaction_details_event = { "path": f"/wallet/channel/transactions", "queryStringParameters": {"order_id": order_id}, "httpMethod": "GET" } transaction_details_lambda_response = self.lambda_client.invoke( FunctionName=WALLETS_SERVICE_ARN, InvocationType='RequestResponse', Payload=json.dumps(transaction_details_event) ) transaction_details_response = json.loads(transaction_details_lambda_response.get('Payload').read()) if transaction_details_response["statusCode"] != 200: raise Exception(f"Failed to fetch transaction details for username{order_id}") transaction_details_response_body = json.loads(transaction_details_response["body"]) order["wallet_transactions"] = transaction_details_response_body["data"]["transactions"] order_status = TransactionStatus.SUCCESS for payment in order["payments"]: if payment["payment_status"] != TransactionStatus.SUCCESS: order_status = payment["payment_status"] break for wallet_transaction in order["wallet_transactions"]: if wallet_transaction["status"] != TransactionStatus.SUCCESS: order_status = wallet_transaction["status"] break order["order_status"] = order_status return {"orders": orders} def get_organizations_from_contract(self): org_details_event = { "path": f"/org", "httpMethod": "GET" } org_details_response = self.boto_client.invoke_lambda( lambda_function_arn=GET_ALL_ORG_API_ARN, invocation_type='RequestResponse', payload=json.dumps(org_details_event) ) if org_details_response["statusCode"] != 200: raise Exception("Failed to get org details") org_details = json.loads(org_details_response["body"])["data"] org_id_name_mapping = {} for org in org_details: org_id_name_mapping[org["org_id"]] = org["org_name"] return org_id_name_mapping def generate_signature_for_open_channel_for_third_party(self, recipient, group_id, amount_in_cogs, expiration, message_nonce, sender_private_key, executor_wallet_address): signature_for_open_channel_for_third_party_body = { 'recipient': recipient, 'group_id': group_id, 'amount_in_cogs': amount_in_cogs, 'expiration': expiration, 'message_nonce': message_nonce, 'signer_key': sender_private_key, 'executor_wallet_address': executor_wallet_address } signature_for_open_channel_for_third_party_payload = { "path": "/signer/open-channel-for-third-party", "body": json.dumps(signature_for_open_channel_for_third_party_body), "httpMethod": "POST" } signature_for_open_channel_for_third_party_response = self.lambda_client.invoke( FunctionName=SIGNER_SERVICE_ARN, InvocationType='RequestResponse', Payload=json.dumps(signature_for_open_channel_for_third_party_payload) ) signature_response = json.loads(signature_for_open_channel_for_third_party_response.get("Payload").read()) if signature_response["statusCode"] != 200: raise Exception(f"Failed to create signature for {signature_for_open_channel_for_third_party_body}") signature_details = json.loads(signature_response["body"]) return signature_details["data"] def cancel_order(self): logger.info("Start of UpdateTransactionStatus::manage_update_canceled_order_in_txn_history") list_of_order_id_for_expired_transaction = self.obj_transaction_history_dao.get_order_id_for_expired_transaction() logger.info(f"List of order_id to be updated with ORDER CANCELED: {list_of_order_id_for_expired_transaction}") update_transaction_status = self.obj_transaction_history_dao.update_transaction_status( list_of_order_id=list_of_order_id_for_expired_transaction, status=OrderStatus.ORDER_CANCELED.value) return update_transaction_status def cancel_order_for_given_order_id(self, order_id): logger.info("UpdateTransactionStatus::cancel_order_for_given_order_id: %s", order_id) transaction_data_dict = self.obj_transaction_history_dao.get_transaction_details_for_given_order_id( order_id=order_id) if transaction_data_dict["status"] == OrderStatus.ORDER_CANCELED.value: return f"Order with order_id {order_id} is already canceled." elif transaction_data_dict["status"] in [OrderStatus.PAYMENT_INITIATED.value, OrderStatus.PAYMENT_INITIATION_FAILED.value, OrderStatus.PAYMENT_EXECUTION_FAILED]: self.obj_transaction_history_dao.update_transaction_status(list_of_order_id=[order_id], status=OrderStatus.ORDER_CANCELED.value) return f"Order with order_id {order_id} is canceled successfully." else: return f"Unable to cancel order with order_id {order_id}" def currency_to_token(self, amount, currency): amount_in_cogs = self.calculate_amount_in_cogs(amount=decimal.Decimal(amount), currency=currency) conversion_data = {"base": currency, "amount": amount, "amount_in_cogs": str(amount_in_cogs), "amount_in_agi": str(self.utils.cogs_to_agi(cogs=amount_in_cogs)), f"{currency}/cogs": str(USD_TO_COGS_CONVERSION_FACTOR), "agi/cogs": str(COGS_TO_AGI)} logger.debug(f"currency_to_token::conversion_data {conversion_data}") return conversion_data
def __init__(self, obj_repo): self.repo = obj_repo self.obj_util = Utils() self.blockchain_util = BlockChainUtil( provider_type="WS_PROVIDER", provider=NETWORKS[NETWORK_ID]["ws_provider"])
import json from common.blockchain_util import BlockChainUtil from common.boto_utils import BotoUtils from common.constant import TransactionStatus from common.logger import get_logger from wallets.config import NETWORKS, NETWORK_ID, REGION_NAME, GET_RAW_EVENT_DETAILS from wallets.infrastructure.repositories.channel_repository import ChannelRepository boto_utils = BotoUtils(region_name=REGION_NAME) channel_repo = ChannelRepository() logger = get_logger(__name__) obj_blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[NETWORK_ID]['http_provider']) class ChannelTransactionStatusService: def __init__(self): pass @staticmethod def get_mpe_processed_transactions_from_event_pub_sub(transaction_list): response = boto_utils.invoke_lambda( payload=json.dumps({ "transaction_hash_list": transaction_list, "contract_name": "MPE" }), lambda_function_arn=GET_RAW_EVENT_DETAILS, invocation_type="RequestResponse") if response["statusCode"] != 200:
def __init__(self, ws_provider, ipfs_url, ipfs_port): self._blockchain_util = BlockChainUtil("WS_PROVIDER", ws_provider) self._s3_util = S3Util(S3_BUCKET_ACCESS_KEY, S3_BUCKET_SECRET_KEY) self._ipfs_util = IPFSUtil(ipfs_url, ipfs_port)
class WalletService: def __init__(self, obj_repo): self.obj_repo = obj_repo def create_and_register_wallet(self): self.obj_blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[NETWORK_ID]['http_provider']) address, private_key = self.obj_blockchain_util.create_account() obj_wallet = Wallet(address=address, private_key=private_key, type=GENERAL_WALLET_TYPE, status=0) registered = self.register_wallet(obj_wallet=obj_wallet) if registered: return obj_wallet.get_wallet() raise Exception("Unable to create and register wallet.") def register_wallet(self, obj_wallet): wallet_details = obj_wallet.get_wallet() obj_wallet_dao = WalletDAO(obj_repo=self.obj_repo) persisted = obj_wallet_dao.insert_wallet_details( address=wallet_details["address"], type=wallet_details["type"], status=wallet_details["status"]) if persisted: return True raise Exception("Unable to register wallet.") def __generate_signature_details(self, recipient, group_id, agi_tokens, expiration, message_nonce, signer_key): data_types = [ "string", "address", "address", "address", "address", "bytes32", "uint256", "uint256", "uint256" ] values = [ "__openChannelByThirdParty", self.mpe_address, EXECUTOR_WALLET_ADDRESS, SIGNER_ADDRESS, recipient, group_id, agi_tokens, expiration, message_nonce ] signature = self.obj_blockchain_util.generate_signature( data_types=data_types, values=values, signer_key=signer_key) v, r, s = Web3.toInt( hexstr="0x" + signature[-2:]), signature[:66], "0x" + signature[66:130] return r, s, v, signature def __calculate_agi_tokens(self, amount, currency): if currency == "USD": agi_tokens = amount else: raise Exception("Currency %s not supported.", currency) return agi_tokens def open_channel_by_third_party(self, order_id, sender, sender_private_key, group_id, amount, currency, recipient): obj_wallet_dao = WalletDAO(obj_repo=self.obj_repo) self.obj_blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[NETWORK_ID]['http_provider']) method_name = "openChannelByThirdParty" self.mpe_address = self.obj_blockchain_util.read_contract_address( net_id=NETWORK_ID, path=MPE_ADDR_PATH, key='address') current_block_no = self.obj_blockchain_util.get_current_block_no() # 1 block no is mined in 15 sec on average, setting expiration as 10 years expiration = current_block_no + (10 * 365 * 24 * 60 * 4) agi_tokens = self.__calculate_agi_tokens(amount=amount, currency=currency) group_id_in_hex = "0x" + base64.b64decode(group_id).hex() r, s, v, signature = self.__generate_signature_details( recipient=recipient, group_id=group_id_in_hex, agi_tokens=agi_tokens, expiration=expiration, message_nonce=current_block_no, signer_key=sender_private_key) positional_inputs = (sender, SIGNER_ADDRESS, recipient, group_id_in_hex, agi_tokens, expiration, current_block_no, v, r, s) transaction_object = self.obj_blockchain_util.create_transaction_object( *positional_inputs, method_name=method_name, address=EXECUTOR_WALLET_ADDRESS, contract_path=MPE_CNTRCT_PATH, contract_address_path=MPE_ADDR_PATH, net_id=NETWORK_ID) raw_transaction = self.obj_blockchain_util.sign_transaction_with_private_key( transaction_object=transaction_object, private_key=EXECUTOR_WALLET_KEY) transaction_hash = self.obj_blockchain_util.process_raw_transaction( raw_transaction=raw_transaction) print("openChannelByThirdParty::transaction_hash", transaction_hash) obj_wallet_dao.insert_channel_history( order_id=order_id, amount=amount, currency=currency, type=method_name, address=sender, signature=signature, request_parameters=str(positional_inputs), transaction_hash=transaction_hash, status=0) return { "transaction_hash": transaction_hash, "signature": signature, "agi_tokens": agi_tokens, "positional_inputs": positional_inputs, "type": method_name } def update_wallet_status(self, address): pass def add_funds_to_channel(self, order_id, channel_id, amount, currency): method_name = "channelAddFunds" agi_tokens = self.__calculate_agi_tokens(amount=amount, currency=currency) positional_inputs = (channel_id, agi_tokens) transaction_object = self.obj_utils.create_transaction_object( *positional_inputs, method_name=method_name, address=EXECUTOR_WALLET_ADDRESS, contract_path=MPE_CNTRCT_PATH, contract_address_path=MPE_ADDR_PATH, net_id=self.net_id) raw_transaction = self.obj_utils.sign_transaction_with_private_key( transaction_object=transaction_object, private_key=EXECUTOR_WALLET_KEY) transaction_hash = self.obj_utils.process_raw_transaction( raw_transaction=raw_transaction) print("channelAddFunds::transaction_hash", transaction_hash) return { "transaction_hash": transaction_hash, "agi_tokens": agi_tokens, "positional_inputs": positional_inputs, "type": method_name }
class Signer: def __init__(self, net_id): self.net_id = net_id self.lambda_client = boto3.client("lambda", region_name=REGION_NAME) self.obj_utils = Utils() self.obj_blockchain_utils = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[self.net_id]["http_provider"], ) self.mpe_address = self.obj_blockchain_utils.read_contract_address( net_id=self.net_id, path=MPE_ADDR_PATH, key="address") self.current_block_no = self.obj_blockchain_utils.get_current_block_no( ) def _get_free_calls_allowed(self, org_id, service_id, group_id): lambda_payload = { "httpMethod": "GET", "pathParameters": { "orgId": org_id, "serviceId": service_id }, } response = self.lambda_client.invoke( FunctionName= GET_SERVICE_DETAILS_FOR_GIVEN_ORG_ID_AND_SERVICE_ID_ARN, InvocationType="RequestResponse", Payload=json.dumps(lambda_payload), ) response_body_raw = json.loads(response.get("Payload").read())["body"] get_service_response = json.loads(response_body_raw) if get_service_response["status"] == "success": groups_data = get_service_response["data"].get("groups", []) for group_data in groups_data: if group_data["group_id"] == group_id: return group_data["free_calls"] raise Exception( "Unable to fetch free calls information for service %s under organization %s for %s group.", service_id, org_id, group_id) def _get_total_calls_made(self, username, org_id, service_id, group_id): lambda_payload = { "httpMethod": "GET", "queryStringParameters": { "organization_id": org_id, "service_id": service_id, "username": username, "group_id": group_id, }, } response = self.lambda_client.invoke( FunctionName=METERING_ARN, InvocationType="RequestResponse", Payload=json.dumps(lambda_payload), ) if response["StatusCode"] == 200: metering_data_raw = json.loads( response.get("Payload").read())["body"] total_calls_made = json.loads(metering_data_raw).get( "total_calls_made", None) if total_calls_made is not None: return total_calls_made raise Exception( "Unable to fetch total calls made for service %s under organization %s for %s group.", service_id, org_id, group_id) def _get_no_of_free_call_available(self, username, org_id, service_id, group_id): token_to_get_free_call, expiry_date_block, signature, current_block_number, daemon_endpoint, free_calls_allowed = self.token_to_get_free_call( username, org_id, service_id, group_id) total_free_call_available = 0 try: total_free_call_available = self._get_no_of_free_calls_from_daemon( username, token_to_get_free_call, expiry_date_block, signature, current_block_number, daemon_endpoint) except Exception as e: logger.info( f"Free call from daemon not available switching to metering {org_id} {service_id} {group_id} {username}" ) total_free_call_made = self._get_total_calls_made( username, org_id, service_id, group_id) total_free_call_available = free_calls_allowed - total_free_call_made return total_free_call_available def _free_calls_allowed(self, username, org_id, service_id, group_id): """ Method to check free calls exists for given user or not. Call monitoring service to get the details """ free_calls_available = self._get_no_of_free_call_available( username, org_id, service_id, group_id) if free_calls_available > 0: return True return False def signature_for_free_call(self, user_data, org_id, service_id, group_id): """ Method to generate signature for free call. """ try: username = user_data["authorizer"]["claims"]["email"] if self._free_calls_allowed(username=username, org_id=org_id, service_id=service_id, group_id=group_id): current_block_no = self.obj_utils.get_current_block_no( ws_provider=NETWORKS[self.net_id]["ws_provider"]) provider = Web3.HTTPProvider( NETWORKS[self.net_id]["http_provider"]) w3 = Web3(provider) message = web3.Web3.soliditySha3( ["string", "string", "string", "string", "uint256"], [ PREFIX_FREE_CALL, username, org_id, service_id, current_block_no ], ) signer_key = SIGNER_KEY if not signer_key.startswith("0x"): signer_key = "0x" + signer_key signature = bytes( w3.eth.account.signHash(defunct_hash_message(message), signer_key).signature) signature = signature.hex() if not signature.startswith("0x"): signature = "0x" + signature return { "snet-free-call-user-id": username, "snet-payment-channel-signature-bin": signature, "snet-current-block-number": current_block_no, "snet-payment-type": "free-call", "snet-free-call-auth-token-bin": "", "snet-free-call-token-expiry-block": 0 } else: raise Exception("Free calls expired for username %s.", username) except Exception as e: logger.error(repr(e)) raise e def signature_for_regular_call(self, user_data, channel_id, nonce, amount): """ Method to generate signature for regular call. """ try: username = user_data["authorizer"]["claims"]["email"] data_types = ["string", "address", "uint256", "uint256", "uint256"] values = [ "__MPE_claim_message", self.mpe_address, channel_id, nonce, amount, ] signature = self.obj_blockchain_utils.generate_signature( data_types=data_types, values=values, signer_key=SIGNER_KEY) return { "snet-payment-channel-signature-bin": signature, "snet-payment-type": "escrow", "snet-payment-channel-id": channel_id, "snet-payment-channel-nonce": nonce, "snet-payment-channel-amount": amount, "snet-current-block-number": self.current_block_no, } except Exception as e: logger.error(repr(e)) raise Exception( "Unable to generate signature for daemon call for username %s", username) def signature_for_state_service(self, user_data, channel_id): """ Method to generate signature for state service. """ try: username = user_data["authorizer"]["claims"]["email"] data_types = ["string", "address", "uint256", "uint256"] values = [ "__get_channel_state", self.mpe_address, channel_id, self.current_block_no, ] signature = self.obj_blockchain_utils.generate_signature( data_types=data_types, values=values, signer_key=SIGNER_KEY) return { "signature": signature, "snet-current-block-number": self.current_block_no, } except Exception as e: logger.error(repr(e)) raise Exception( "Unable to generate signature for daemon call for username %s", username) def signature_for_open_channel_for_third_party(self, recipient, group_id, amount_in_cogs, expiration, message_nonce, sender_private_key, executor_wallet_address): data_types = [ "string", "address", "address", "address", "address", "bytes32", "uint256", "uint256", "uint256" ] values = [ "__openChannelByThirdParty", self.mpe_address, executor_wallet_address, SIGNER_ADDRESS, recipient, group_id, amount_in_cogs, expiration, message_nonce ] signature = self.obj_blockchain_utils.generate_signature( data_types=data_types, values=values, signer_key=sender_private_key) v, r, s = Web3.toInt( hexstr="0x" + signature[-2:]), signature[:66], "0x" + signature[66:130] return {"r": r, "s": s, "v": v, "signature": signature} def _get_no_of_free_calls_from_daemon(self, email, token_to_get_free_call, expiry_date_block, signature, current_block_number, daemon_endpoint): request = state_service_pb2.FreeCallStateRequest() request.user_id = email request.token_for_free_call = token_to_get_free_call request.token_expiry_date_block = expiry_date_block request.signature = signature request.current_block = current_block_number endpoint_object = urlparse(daemon_endpoint) if endpoint_object.port is not None: channel_endpoint = endpoint_object.hostname + ":" + str( endpoint_object.port) else: channel_endpoint = endpoint_object.hostname if endpoint_object.scheme == "http": channel = grpc.insecure_channel(channel_endpoint) elif endpoint_object.scheme == "https": channel = grpc.secure_channel(channel_endpoint, grpc.ssl_channel_credentials()) else: raise ValueError( 'Unsupported scheme in service metadata ("{}")'.format( endpoint_object.scheme)) stub = state_service_pb2_grpc.FreeCallStateServiceStub(channel) response = stub.GetFreeCallsAvailable(request) return response.free_calls_available def _is_free_call_available(self, email, token_for_free_call, expiry_date_block, signature, current_block_number, daemon_endpoint): if self._get_no_of_free_calls_from_daemon( email, token_for_free_call, expiry_date_block, signature, current_block_number, daemon_endpoint) > 0: return True return False def _get_daemon_endpoint_and_free_call_for_group(self, org_id, service_id, group_id): lambda_payload = { "httpMethod": "GET", "pathParameters": { "orgId": org_id, "serviceId": service_id }, } response = self.lambda_client.invoke( FunctionName= GET_SERVICE_DETAILS_FOR_GIVEN_ORG_ID_AND_SERVICE_ID_ARN, InvocationType="RequestResponse", Payload=json.dumps(lambda_payload), ) response_body_raw = json.loads(response.get("Payload").read())["body"] get_service_response = json.loads(response_body_raw) if get_service_response["status"] == "success": groups_data = get_service_response["data"].get("groups", []) for group_data in groups_data: if group_data["group_id"] == group_id: return group_data["endpoints"][0][ "endpoint"], group_data.get("free_calls", 0) raise Exception( "Unable to fetch daemon Endpoint information for service %s under organization %s for %s group.", service_id, org_id, group_id) def token_to_get_free_call(self, email, org_id, service_id, group_id): signer_public_key_checksum = Web3.toChecksumAddress(SIGNER_ADDRESS) current_block_number = self.obj_blockchain_utils.get_current_block_no() expiry_date_block = current_block_number + FREE_CALL_EXPIRY token_to_get_free_call = self.obj_blockchain_utils.generate_signature_bytes( ["string", "address", "uint256"], [email, signer_public_key_checksum, expiry_date_block], SIGNER_KEY) signature = self.obj_blockchain_utils.generate_signature_bytes([ "string", "string", "string", "string", "string", "uint256", "bytes32" ], [ "__prefix_free_trial", email, org_id, service_id, group_id, current_block_number, token_to_get_free_call ], SIGNER_KEY) daemon_endpoint, free_calls_allowed = self._get_daemon_endpoint_and_free_call_for_group( org_id, service_id, group_id) logger.info( f"Got daemon endpoint {daemon_endpoint} for org {org_id} service {service_id} group {group_id}" ) return token_to_get_free_call, expiry_date_block, signature, current_block_number, daemon_endpoint, free_calls_allowed def token_to_make_free_call(self, email, org_id, service_id, group_id, user_public_key): token_to_get_free_call, expiry_date_block, signature, current_block_number, daemon_endpoint, free_calls_allowed = self.token_to_get_free_call( email, org_id, service_id, group_id) token_with_expiry_to_make_free_call = "" if self._is_free_call_available(email, token_to_get_free_call, expiry_date_block, signature, current_block_number, daemon_endpoint): token_with_expiry_to_make_free_call = self.obj_blockchain_utils.generate_signature_bytes( ["string", "address", "uint256"], [ email, Web3.toChecksumAddress(user_public_key), expiry_date_block ], SIGNER_KEY) return { "token_to_make_free_call": token_with_expiry_to_make_free_call.hex(), "token_expiration_block": expiry_date_block }
class TestUtils(unittest.TestCase): def setUp(self): self.net_id = 3 self.http_provider = Web3.HTTPProvider( NETWORKS[self.net_id]['http_provider']) self.obj_utils = BlockChainUtil(provider_type="HTTP_PROVIDER", provider=self.http_provider) self.mpe_address = self.obj_utils.read_contract_address( net_id=self.net_id, path=MPE_ADDR_PATH, key='address') self.recipient = "0x9c302750c50307D3Ad88eaA9a6506874a15cE4Cb" self.group_id = "0x" + base64.b64decode( "DS2OoKSfGE/7hAO/023psl4Qdj0MJvYsreJbCoAHVSc=").hex() self.agi_tokens = 1 self.current_block_no = self.obj_utils.get_current_block_no() self.expiration = self.current_block_no + 10000000 self.channel_id = 0 def generate_signature(self, message_nonce, signer_key): data_types = [ "string", "address", "address", "address", "address", "bytes32", "uint256", "uint256", "uint256" ] values = [ "__openChannelByThirdParty", self.mpe_address, EXECUTOR_ADDRESS, SIGNER_ADDRESS, self.recipient, self.group_id, self.agi_tokens, self.expiration, message_nonce ] signature = self.obj_utils.generate_signature(data_types=data_types, values=values, signer_key=signer_key) v, r, s = Web3.toInt( hexstr="0x" + signature[-2:]), signature[:66], "0x" + signature[66:130] assert (v == 27 or v == 28) assert (len(r) == 66) assert (len(s) == 66) assert (len(signature) == 132) return r, s, v, signature def test_create_account(self): address, private_key = self.obj_utils.create_account() assert (Web3.isAddress(address) == True) return address, private_key def test_create_transaction_object1(self): method_name = "openChannelByThirdParty" sender, sender_private_key = self.test_create_account() message_nonce = self.obj_utils.get_current_block_no() r, s, v, signature = self.generate_signature( message_nonce=message_nonce, signer_key=sender_private_key) positional_inputs = (sender, SIGNER_ADDRESS, self.recipient, self.group_id, self.agi_tokens, self.expiration, message_nonce, v, r, s) transaction_object = self.obj_utils.create_transaction_object( *positional_inputs, method_name=method_name, address=EXECUTOR_ADDRESS, contract_path=MPE_CNTRCT_PATH, contract_address_path=MPE_ADDR_PATH, net_id=self.net_id) print(transaction_object) raw_transaction = self.obj_utils.sign_transaction_with_private_key( transaction_object=transaction_object, private_key=EXECUTOR_KEY) transaction_hash = self.obj_utils.process_raw_transaction( raw_transaction=raw_transaction) print("openChannelByThirdParty::transaction_hash", transaction_hash) def test_create_transaction_object2(self): method_name = "channelAddFunds" positional_inputs = (self.channel_id, self.agi_tokens) transaction_object = self.obj_utils.create_transaction_object( *positional_inputs, method_name=method_name, address=EXECUTOR_ADDRESS, contract_path=MPE_CNTRCT_PATH, contract_address_path=MPE_ADDR_PATH, net_id=self.net_id) print(transaction_object) raw_transaction = self.obj_utils.sign_transaction_with_private_key( transaction_object=transaction_object, private_key=EXECUTOR_KEY) transaction_hash = self.obj_utils.process_raw_transaction( raw_transaction=raw_transaction) print("channelAddFunds::transaction_hash", transaction_hash)
class OrganizationEventConsumer(EventConsumer): _connection = Repository(NETWORK_ID, NETWORKS=NETWORKS) _organization_repository = OrganizationRepository(_connection) _service_repository = ServiceRepository(_connection) def __init__(self, ws_provider, ipfs_url, ipfs_port): self._ipfs_util = IPFSUtil(ipfs_url, ipfs_port) self._blockchain_util = BlockChainUtil("WS_PROVIDER", ws_provider) self._s3_util = S3Util(S3_BUCKET_ACCESS_KEY, S3_BUCKET_SECRET_KEY) def on_event(self, event): pass def _push_asset_to_s3_using_hash(self, hash, org_id, service_id): io_bytes = self._ipfs_util.read_bytesio_from_ipfs( hash.lstrip("ipfs://")) filename = hash.split("/")[1] if service_id: s3_filename = ASSETS_PREFIX + "/" + org_id + "/" + service_id + "/" + filename else: s3_filename = ASSETS_PREFIX + "/" + org_id + "/" + filename new_url = self._s3_util.push_io_bytes_to_s3(s3_filename, ASSETS_BUCKET_NAME, io_bytes) return new_url def _get_new_assets_url(self, org_id, new_ipfs_data): new_assets_hash = new_ipfs_data.get('assets', {}) existing_assets_hash = {} existing_assets_url = {} existing_organization = self._organization_repository.get_organization( org_id) if existing_organization: existing_assets_hash = json.loads( existing_organization["assets_hash"]) existing_assets_url = json.loads( existing_organization["org_assets_url"]) new_assets_url_mapping = self._comapre_assets_and_push_to_s3( existing_assets_hash, new_assets_hash, existing_assets_url, org_id, "") return new_assets_url_mapping def _get_org_id_from_event(self, event): event_org_data = eval(event['data']['json_str']) org_id_bytes = event_org_data['orgId'] org_id = Web3.toText(org_id_bytes).rstrip("\x00") return org_id def _get_registry_contract(self): net_id = NETWORK_ID base_contract_path = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..', 'node_modules', 'singularitynet-platform-contracts')) registry_contract = self._blockchain_util.get_contract_instance( base_contract_path, "REGISTRY", net_id) return registry_contract def _get_org_details_from_blockchain(self, event): logger.info(f"processing org event {event}") registry_contract = self._get_registry_contract() org_id = self._get_org_id_from_event(event) blockchain_org_data = registry_contract.functions.getOrganizationById( org_id.encode('utf-8')).call() org_metadata_uri = Web3.toText( blockchain_org_data[2]).rstrip("\x00").lstrip("ipfs://") ipfs_org_metadata = self._ipfs_util.read_file_from_ipfs( org_metadata_uri) return org_id, blockchain_org_data, ipfs_org_metadata, org_metadata_uri
class TestUtils(unittest.TestCase): def setUp(self): self.net_id = 3 self.http_provider = Web3.HTTPProvider( NETWORKS[self.net_id]['http_provider']) self.obj_utils = BlockChainUtil(provider_type="HTTP_PROVIDER", provider=self.http_provider) self.mpe_address = self.obj_utils.read_contract_address( net_id=self.net_id, path=MPE_ADDR_PATH, key='address') self.recipient = "0x9c302750c50307D3Ad88eaA9a6506874a15cE4Cb" self.group_id = "0x" + base64.b64decode( "DS2OoKSfGE/7hAO/023psl4Qdj0MJvYsreJbCoAHVSc=").hex() self.agi_tokens = 1 self.current_block_no = self.obj_utils.get_current_block_no() self.expiration = self.current_block_no + 10000000 self.channel_id = 0 def generate_signature(self, message_nonce, signer_key): data_types = [ "string", "address", "address", "address", "address", "bytes32", "uint256", "uint256", "uint256" ] values = [ "__openChannelByThirdParty", self.mpe_address, EXECUTOR_ADDRESS, SIGNER_ADDRESS, self.recipient, self.group_id, self.agi_tokens, self.expiration, message_nonce ] signature = self.obj_utils.generate_signature(data_types=data_types, values=values, signer_key=signer_key) v, r, s = Web3.toInt( hexstr="0x" + signature[-2:]), signature[:66], "0x" + signature[66:130] assert (v == 27 or v == 28) assert (len(r) == 66) assert (len(s) == 66) assert (len(signature) == 132) return r, s, v, signature def test_create_account(self): address, private_key = self.obj_utils.create_account() assert (Web3.isAddress(address) == True) return address, private_key def test_create_transaction_object1(self): method_name = "openChannelByThirdParty" sender, sender_private_key = self.test_create_account() message_nonce = self.obj_utils.get_current_block_no() r, s, v, signature = self.generate_signature( message_nonce=message_nonce, signer_key=sender_private_key) positional_inputs = (sender, SIGNER_ADDRESS, self.recipient, self.group_id, self.agi_tokens, self.expiration, message_nonce, v, r, s) transaction_object = self.obj_utils.create_transaction_object( *positional_inputs, method_name=method_name, address=EXECUTOR_ADDRESS, contract_path=MPE_CNTRCT_PATH, contract_address_path=MPE_ADDR_PATH, net_id=self.net_id) print(transaction_object) raw_transaction = self.obj_utils.sign_transaction_with_private_key( transaction_object=transaction_object, private_key=EXECUTOR_KEY) transaction_hash = self.obj_utils.process_raw_transaction( raw_transaction=raw_transaction) print("openChannelByThirdParty::transaction_hash", transaction_hash) def test_create_transaction_object2(self): method_name = "channelAddFunds" positional_inputs = (self.channel_id, self.agi_tokens) transaction_object = self.obj_utils.create_transaction_object( *positional_inputs, method_name=method_name, address=EXECUTOR_ADDRESS, contract_path=MPE_CNTRCT_PATH, contract_address_path=MPE_ADDR_PATH, net_id=self.net_id) print(transaction_object) raw_transaction = self.obj_utils.sign_transaction_with_private_key( transaction_object=transaction_object, private_key=EXECUTOR_KEY) transaction_hash = self.obj_utils.process_raw_transaction( raw_transaction=raw_transaction) print("channelAddFunds::transaction_hash", transaction_hash) def test_generate_signature_for_state_service(self): channel_id = 1 data_types = ["string", "address", "uint256", "uint256"] self.current_block_no = 6487832 values = [ "__get_channel_state", self.mpe_address, channel_id, self.current_block_no ] signature = self.obj_utils.generate_signature(data_types=data_types, values=values, signer_key=SIGNER_KEY) v, r, s = Web3.toInt( hexstr="0x" + signature[-2:]), signature[:66], "0x" + signature[66:130] assert ( signature == "0x0b9bb258a0f975328fd9cd9608bd9b570e7b68cad8d337c940e32b9413e348437dd3614f9c6f776b1eb62d521a5794204a010f581721f167c5b26de0928b139d1c" ) def test_generate_signature_for_daemon_call(self): channel_id = 1 amount = 10 nonce = 1 data_types = ["string", "address", "uint256", "uint256", "uint256"] values = [ "__MPE_claim_message", self.mpe_address, channel_id, nonce, amount ] signature = self.obj_utils.generate_signature(data_types=data_types, values=values, signer_key=SIGNER_KEY) v, r, s = Web3.toInt( hexstr="0x" + signature[-2:]), signature[:66], "0x" + signature[66:130] assert ( signature == "0x7e50ac20909da29f72ed2ab9cf6c6375f853d8eddfcf3ce33806a4e27b30bcbd5366c41a59647467f0519b0bfc89a50d890b683cd797d5566ba03937f82819c41b" )
def __init__(self, ws_provider): self.blockchain_util = BlockChainUtil("WS_PROVIDER", ws_provider)
class MPE: def __init__(self, obj_repo): self.repo = obj_repo self.obj_util = Utils() self.blockchain_util = BlockChainUtil( provider_type="WS_PROVIDER", provider=NETWORKS[NETWORK_ID]["ws_provider"]) def get_channels(self, user_address, org_id=None, service_id=None, group_id=None): if user_address and org_id and group_id: return self.get_channels_by_user_address_org_group( user_address=user_address, org_id=org_id, group_id=group_id) elif user_address is not None: return self.get_channels_by_user_address(user_address, service_id, org_id) else: raise Exception("Invalid Request") def get_channels_by_user_address_v2(self, user_address): last_block_no = self.blockchain_util.get_current_block_no() logger.info(f"got block number {last_block_no}") channel_details_query = "SELECT mc.channel_id, mc.sender, mc.recipient, mc.groupId as group_id, " \ "mc.balance_in_cogs, mc.pending, mc.nonce, mc.consumed_balance, mc.expiration, " \ "mc.signer, og.org_id, " \ "org.organization_name, IF(mc.expiration > %s, 'active','inactive') AS status, " \ "og.group_name, org.org_assets_url " \ "FROM mpe_channel AS mc JOIN org_group AS og ON mc.groupId = og.group_id " \ "JOIN organization AS org ON og.org_id = org.org_id WHERE mc.sender = %s " params = [last_block_no, user_address] channel_details = self.repo.execute(channel_details_query, params) self.obj_util.clean(channel_details) channel_details_response = { "wallet_address": user_address, "organizations": self.segregate_org_channel_details(channel_details) } return channel_details_response def segregate_org_channel_details(self, raw_channel_data): org_data = {} for channel_record in raw_channel_data: org_id = channel_record["org_id"] group_id = channel_record["group_id"] if org_id not in org_data: org_data[org_id] = { "org_name": channel_record["organization_name"], "org_id": org_id, "hero_image": json.loads(channel_record["org_assets_url"]).get( "hero_image", ""), "groups": {} } if group_id not in org_data[org_id]["groups"]: org_data[org_id]["groups"][group_id] = { "group_id": group_id, "group_name": channel_record["group_name"], "channels": [] } channel = { "channel_id": channel_record["channel_id"], "recipient": channel_record["recipient"], 'balance_in_cogs': channel_record['balance_in_cogs'], 'consumed_balance': channel_record["consumed_balance"], 'current_balance': str( decimal.Decimal(channel_record['balance_in_cogs']) - decimal.Decimal(channel_record["consumed_balance"])), "pending": channel_record["pending"], "nonce": channel_record["nonce"], "expiration": channel_record["expiration"], "signer": channel_record["signer"], "status": channel_record["status"] } org_data[org_id]["groups"][group_id]["channels"].append(channel) for org_id in org_data: org_data[org_id]["groups"] = list( org_data[org_id]["groups"].values()) return list(org_data.values()) def get_channels_by_user_address(self, user_address, service_id, org_id): last_block_no = self.blockchain_util.get_current_block_no() params = [last_block_no] print('Inside get_channel_info::user_address', user_address, '|', org_id, '|', service_id) sub_qry = "" if user_address is not None and service_id is not None and org_id is not None: sub_qry = " AND S.org_id = %s AND S.service_id = %s " params.append(org_id) params.append(service_id) params.append(user_address) raw_channel_dta = self.repo.execute( 'SELECT C.*, E.*, IF(C.expiration > %s, "active","inactive") AS status FROM ' 'service_group G, mpe_channel C, service_endpoint E, service S WHERE G.group_id = C.groupId AND ' 'G.group_id = E.group_id and S.row_id = E.service_row_id and E.service_row_id = G.service_row_id ' 'AND S.is_curated = 1 ' + sub_qry + ' AND C.sender = %s ORDER BY C.expiration DESC', params) self.obj_util.clean(raw_channel_dta) channel_dta = {} for rec in raw_channel_dta: group_id = rec['groupId'] if group_id not in channel_dta.keys(): channel_dta[group_id] = { 'group_id': group_id, 'org_id': rec['org_id'], 'service_id': rec['service_id'], 'group': { "endpoints": [] }, 'channels': [] } channel = { 'channel_id': rec['channel_id'], 'recipient': rec['recipient'], 'balance_in_cogs': rec['balance_in_cogs'], 'consumed_balance': rec["consumed_balance"], 'current_balance': str( decimal.Decimal(rec['balance_in_cogs']) - decimal.Decimal(rec["consumed_balance"])), 'pending': rec['pending'], 'nonce': rec['nonce'], 'expiration': rec['expiration'], 'signer': rec['signer'], 'status': rec['status'] } endpoint = { 'endpoint': rec['endpoint'], 'is_available': rec['endpoint'], 'last_check_timestamp': rec['last_check_timestamp'] } channel_dta[group_id]['group']['endpoints'].append(endpoint) channel_dta[group_id]['channels'].append(channel) return list(channel_dta.values()) def get_channels_by_user_address_org_group(self, user_address, org_id=None, group_id=None): last_block_no = self.blockchain_util.get_current_block_no() params = [last_block_no, org_id, group_id, user_address] raw_channel_data = self.repo.execute( "SELECT C.* , OG.payment, OG.org_id, IF(C.expiration > %s, 'active','inactive') AS status FROM " "mpe_channel C JOIN org_group OG ON C.groupId = OG.group_id " "where OG.org_id = %s and C.groupId = %s and C.sender = %s", params) self.obj_util.clean(raw_channel_data) channel_data = {'group_id': group_id, 'org_id': org_id, 'channels': []} for record in raw_channel_data: record["payment"] = json.loads(record["payment"]) if record["recipient"] == record["payment"]["payment_address"]: channel = { 'channel_id': record['channel_id'], 'recipient': record['recipient'], 'balance_in_cogs': record['balance_in_cogs'], 'consumed_balance': record["consumed_balance"], 'current_balance': str( decimal.Decimal(record['balance_in_cogs']) - decimal.Decimal(record["consumed_balance"])), 'pending': record['pending'], 'nonce': record['nonce'], 'expiration': record['expiration'], 'signer': record['signer'], 'status': record['status'] } channel_data['channels'].append(channel) return channel_data def get_channel_data_by_group_id_and_channel_id(self, group_id, channel_id): try: result = self.repo.execute( "SELECT * FROM mpe_channel WHERE groupId = %s AND channel_id = %s", [group_id, channel_id]) self.obj_util.clean(result) return result except Exception as e: print(repr(e)) raise e def update_consumed_balance(self, channel_id, authorized_amount, full_amount, nonce): mpe_repo = MPERepository(self.repo) channel = mpe_repo.get_mpe_channels(channel_id) if len(channel) != 0 and self.validate_channel_consume_data( channel[0], authorized_amount, full_amount, nonce): mpe_repo.update_consumed_balance(channel_id, authorized_amount) else: raise Exception("Channel validation failed") return {} @staticmethod def validate_channel_consume_data(channel_details, authorized_amount, full_amount, nonce): if channel_details["consumed_balance"] < authorized_amount \ and channel_details["balance_in_cogs"] == full_amount \ and channel_details["nonce"] == nonce: return True return False
class WalletService: def __init__(self, repo): self.repo = repo self.boto_utils = BotoUtils(region_name=REGION_NAME) self.blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[NETWORK_ID]['http_provider']) self.utils = Utils() self.channel_dao = ChannelDAO(repo=self.repo) self.wallet_dao = WalletDAO(repo=self.repo) def create_and_register_wallet(self, username): address, private_key = self.blockchain_util.create_account() wallet = Wallet(address=address, private_key=private_key, type=GENERAL_WALLET_TYPE, status=WalletStatus.ACTIVE.value) self._register_wallet(wallet, username) return wallet.to_dict() def _register_wallet(self, wallet, username): existing_wallet = self.wallet_dao.get_wallet_details(wallet) if len(existing_wallet) == 0: self.wallet_dao.insert_wallet(wallet) self.wallet_dao.add_user_for_wallet(wallet, username) def register_wallet(self, wallet_address, wallet_type, status, username): wallet = Wallet(address=wallet_address, type=wallet_type, status=status) self._register_wallet(wallet, username) return wallet.to_dict() def remove_user_wallet(self, username): self.wallet_dao.remove_user_wallet(username) def get_wallet_details(self, username): """ Method to get wallet details for a given username. """ logger.info(f"Fetching wallet details for {username}") wallet_data = self.wallet_dao.get_wallet_data_by_username(username) self.utils.clean(wallet_data) logger.info( f"Fetched {len(wallet_data)} wallets for username: {username}") wallet_response = {"username": username, "wallets": wallet_data} return wallet_response def __generate_signature_details(self, recipient, group_id, agi_tokens, expiration, message_nonce, signer_key): data_types = [ "string", "address", "address", "address", "address", "bytes32", "uint256", "uint256", "uint256" ] values = [ "__openChannelByThirdParty", self.mpe_address, self.EXECUTOR_WALLET_ADDRESS, SIGNER_ADDRESS, recipient, group_id, agi_tokens, expiration, message_nonce ] signature = self.blockchain_util.generate_signature( data_types=data_types, values=values, signer_key=signer_key) v, r, s = Web3.toInt( hexstr="0x" + signature[-2:]), signature[:66], "0x" + signature[66:130] return r, s, v, signature def __calculate_amount_in_cogs(self, amount, currency): if currency == "USD": amount_in_cogs = round(amount) else: raise Exception("Currency %s not supported.", currency) return amount_in_cogs def record_create_channel_event(self, payload): current_time = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S") if not self.channel_dao.persist_create_channel_event( payload, current_time): raise Exception("Failed to create record") return {} def open_channel_by_third_party(self, order_id, sender, signature, r, s, v, group_id, org_id, amount, currency, recipient, current_block_no, amount_in_cogs): self.EXECUTOR_WALLET_ADDRESS = self.boto_utils.get_ssm_parameter( EXECUTOR_ADDRESS) self.EXECUTOR_WALLET_KEY = self.boto_utils.get_ssm_parameter( EXECUTOR_KEY) method_name = "openChannelByThirdParty" self.mpe_address = self.blockchain_util.read_contract_address( net_id=NETWORK_ID, path=MPE_ADDR_PATH, key='address') # 1 block no is mined in 15 sec on average, setting expiration as 10 years expiration = current_block_no + (10 * 365 * 24 * 60 * 4) # amount_in_cogs = self.__calculate_amount_in_cogs(amount=amount, currency=currency) self.__validate__cogs(amount_in_cogs=amount_in_cogs) group_id_in_hex = "0x" + base64.b64decode(group_id).hex() positional_inputs = (sender, SIGNER_ADDRESS, recipient, group_id_in_hex, amount_in_cogs, expiration, current_block_no, v, r, s) transaction_object = self.blockchain_util.create_transaction_object( *positional_inputs, method_name=method_name, address=self.EXECUTOR_WALLET_ADDRESS, contract_path=MPE_CNTRCT_PATH, contract_address_path=MPE_ADDR_PATH, net_id=NETWORK_ID) raw_transaction = self.blockchain_util.sign_transaction_with_private_key( transaction_object=transaction_object, private_key=self.EXECUTOR_WALLET_KEY) transaction_hash = self.blockchain_util.process_raw_transaction( raw_transaction=raw_transaction) logger.info( "openChannelByThirdParty::transaction_hash : %s for order_id : %s", transaction_hash, order_id) self.channel_dao.insert_channel_history( order_id=order_id, amount=amount, currency=currency, group_id=group_id, org_id=org_id, type=method_name, recipient=recipient, address=sender, signature=signature, request_parameters=str(positional_inputs), transaction_hash=transaction_hash, status=TransactionStatus.PENDING) return { "transaction_hash": transaction_hash, "signature": signature, "amount_in_cogs": amount_in_cogs, "type": method_name } def set_default_wallet(self, username, address): self.wallet_dao.set_default_wallet(username=username, address=address) return "OK" def add_funds_to_channel(self, org_id, group_id, channel_id, sender, recipient, order_id, amount, currency, amount_in_cogs): self.EXECUTOR_WALLET_ADDRESS = self.boto_utils.get_ssm_parameter( EXECUTOR_ADDRESS) self.EXECUTOR_WALLET_KEY = self.boto_utils.get_ssm_parameter( EXECUTOR_KEY) method_name = "channelAddFunds" # amount_in_cogs = self.__calculate_amount_in_cogs(amount=amount, currency=currency) self.__validate__cogs(amount_in_cogs=amount_in_cogs) positional_inputs = (channel_id, amount_in_cogs) transaction_object = self.blockchain_util.create_transaction_object( *positional_inputs, method_name=method_name, address=self.EXECUTOR_WALLET_ADDRESS, contract_path=MPE_CNTRCT_PATH, contract_address_path=MPE_ADDR_PATH, net_id=NETWORK_ID) raw_transaction = self.blockchain_util.sign_transaction_with_private_key( transaction_object=transaction_object, private_key=self.EXECUTOR_WALLET_KEY) transaction_hash = self.blockchain_util.process_raw_transaction( raw_transaction=raw_transaction) logger.info("channelAddFunds::transaction_hash: %s for order_id: %s", transaction_hash, order_id) self.channel_dao.insert_channel_history( order_id=order_id, amount=amount, currency=currency, group_id=group_id, org_id=org_id, type=method_name, recipient=recipient, address=sender, signature=None, request_parameters=str(positional_inputs), transaction_hash=transaction_hash, status=TransactionStatus.PENDING) return { "transaction_hash": transaction_hash, "amount_in_cogs": amount_in_cogs, "type": method_name } def get_transactions_from_username_recipient(self, username, org_id, group_id): logger.info( f"Fetching transactions for {username} to org_id: {org_id} group_id: {org_id}" ) channel_data = self.channel_dao.get_channel_transactions_for_username_recipient( username=username, group_id=group_id, org_id=org_id) self.utils.clean(channel_data) logger.info(f"Fetched {len(channel_data)} transactions") transaction_details = {"username": username, "wallets": []} wallet_transactions = dict() for rec in channel_data: sender_address = rec["address"] if rec["address"] not in wallet_transactions: wallet_transactions[rec["address"]] = { "address": sender_address, "is_default": rec["is_default"], "type": rec["type"], "transactions": [] } if rec['recipient'] is None: continue transaction = { "org_id": org_id, "group_id": group_id, "recipient": rec["recipient"], "amount": rec["amount"], "transaction_type": rec["transaction_type"], "currency": rec["currency"], "status": rec["status"], "created_at": rec["created_at"], } wallet_transactions[sender_address]["transactions"].append( transaction) for key in wallet_transactions: wallet = wallet_transactions[key] transaction_details["wallets"].append(wallet) return transaction_details def get_channel_transactions_against_order_id(self, order_id): transaction_history = self.channel_dao.get_channel_transactions_against_order_id( order_id) for record in transaction_history: record["created_at"] = record["created_at"].strftime( "%Y-%m-%d %H:%M:%S") return {"order_id": order_id, "transactions": transaction_history} def __validate__cogs(self, amount_in_cogs): if amount_in_cogs < MINIMUM_AMOUNT_IN_COGS_ALLOWED: raise Exception( "Insufficient amount to buy minimum amount in cogs allowed.")
class RegistryBlockChainUtil: def __init__(self, env_type): self.__env_type = env_type if env_type == EnvironmentType.MAIN.value: self.__network_id = NETWORK_ID self.__contract_path = REG_CNTRCT_PATH self.__executor_address = "" self.__contract_address_path = REG_ADDR_PATH self.__blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=NETWORKS[self.__network_id]['http_provider']) elif env_type == EnvironmentType.TEST.value: self.__contract_path = TEST_REG_CNTRCT_PATH self.__contract_address_path = TEST_REG_ADDR_PATH self.__executor_address = BLOCKCHAIN_TEST_ENV["publisher_address"] self.__network_id = BLOCKCHAIN_TEST_ENV["network_id"] self.__blockchain_util = BlockChainUtil( provider_type="HTTP_PROVIDER", provider=BLOCKCHAIN_TEST_ENV['http_provider']) else: raise MethodNotImplemented() def is_org_published(self, org_id): contract = self.__blockchain_util.load_contract( path=self.__contract_path) contract_address = self.__blockchain_util.read_contract_address( net_id=self.__network_id, path=self.__contract_address_path, key='address') return self.__organization_exist_in_blockchain(org_id, contract, contract_address) def __organization_exist_in_blockchain(self, org_id, contract, contract_address): method_name = "getOrganizationById" positional_inputs = (web3.Web3.toHex(text=org_id), ) contract = self.__blockchain_util.contract_instance( contract_abi=contract, address=contract_address) org_data = self.__blockchain_util.call_contract_function( contract=contract, contract_function=method_name, positional_inputs=positional_inputs) logger.info(f"Org data :: {org_data}") org_found = org_data[0] return org_found def __generate_blockchain_transaction_for_test_environment( self, *positional_inputs, method_name): transaction_object = self.__blockchain_util.create_transaction_object( *positional_inputs, method_name=method_name, address=self.__executor_address, contract_path=self.__contract_path, contract_address_path=self.__contract_address_path, net_id=self.__network_id) return transaction_object def __make_trasaction(self, *positional_inputs, method_name): if self.__env_type == EnvironmentType.TEST.value: executor_key = BotoUtils(REGION_NAME).get_ssm_parameter( BLOCKCHAIN_TEST_ENV["publisher_private_key"]) transaction_object = self.__generate_blockchain_transaction_for_test_environment( *positional_inputs, method_name=method_name) else: raise EnvironmentNotFoundException() raw_transaction = self.__blockchain_util.sign_transaction_with_private_key( transaction_object=transaction_object, private_key=executor_key) transaction_hash = self.__blockchain_util.process_raw_transaction( raw_transaction=raw_transaction) return transaction_hash def __update_organization_in_blockchain(self, org_id, metadata_uri): method_name = "changeOrganizationMetadataURI" positional_inputs = (web3.Web3.toHex(text=org_id), ipfsuri_to_bytesuri(metadata_uri)) transaction_hash = self.__make_trasaction(*positional_inputs, method_name=method_name) logger.info( f"transaction hash {transaction_hash} generated while registering organization " f"{org_id} in {self.__env_type} blockchain environment.") return transaction_hash def __register_organization_in_blockchain(self, org_id, metadata_uri, members): method_name = "createOrganization" positional_inputs = (web3.Web3.toHex(text=org_id), ipfsuri_to_bytesuri(metadata_uri), members) transaction_hash = self.__make_trasaction(*positional_inputs, method_name=method_name) logger.info( f"transaction hash {transaction_hash} generated while registering organization " f"{org_id} in {self.__env_type} blockchain environment.") return transaction_hash def publish_organization_to_test_network(self, organization): metadata_uri = organization.metadata_ipfs_uri members = [] org_id = organization.id if self.__env_type == EnvironmentType.TEST.value: if self.is_org_published(org_id): return self.__update_organization_in_blockchain( org_id, metadata_uri) else: return self.__register_organization_in_blockchain( org_id, metadata_uri, members) else: raise EnvironmentNotFoundException() def __service_exist_in_blockchain(self, org_id, service_id, contract, contract_address): method_name = "getServiceRegistrationById" positional_inputs = (web3.Web3.toHex(text=org_id), web3.Web3.toHex(text=service_id)) contract = self.__blockchain_util.contract_instance( contract_abi=contract, address=contract_address) service_data = self.__blockchain_util.call_contract_function( contract=contract, contract_function=method_name, positional_inputs=positional_inputs) logger.info(f"Services :: {service_data}") service_found = service_data[0] return service_found def update_service_in_blockchain(self, org_id, service_id, metadata_uri): method_name = "updateServiceRegistration" positional_inputs = (web3.Web3.toHex(text=org_id), web3.Web3.toHex(text=service_id), ipfsuri_to_bytesuri(metadata_uri)) transaction_hash = self.__make_trasaction(*positional_inputs, method_name=method_name) logger.info( f"transaction hash {transaction_hash} generated while " f"updating service {service_id} in {self.__env_type} blockchain environment." ) return transaction_hash def register_service_in_blockchain(self, org_id, service_id, metadata_uri, tags): method_name = "createServiceRegistration" positional_inputs = (web3.Web3.toHex(text=org_id), web3.Web3.toHex(text=service_id), ipfsuri_to_bytesuri(metadata_uri), [web3.Web3.toHex(text=tag) for tag in tags]) transaction_hash = self.__make_trasaction(*positional_inputs, method_name=method_name) logger.info( f"transaction hash {transaction_hash} generated while registering service {service_id} " f"in {self.__env_type} blockchain environment.") return transaction_hash def is_service_published(self, org_id, service_id): contract = self.__blockchain_util.load_contract( path=self.__contract_path) contract_address = self.__blockchain_util.read_contract_address( net_id=self.__network_id, path=self.__contract_address_path, key='address') return self.__service_exist_in_blockchain(org_id, service_id, contract, contract_address) def register_or_update_service_in_blockchain(self, org_id, service_id, metadata_uri, tags): if not self.is_org_published(org_id=org_id): raise OrganizationNotFoundException() if self.is_service_published(org_id=org_id, service_id=service_id): transaction_hash = self.update_service_in_blockchain( org_id, service_id, metadata_uri) else: transaction_hash = self.register_service_in_blockchain( org_id, service_id, metadata_uri, tags) return transaction_hash
from common.blockchain_util import BlockChainUtil from common.utils import Utils from rfai.config import NETWORK from rfai.dao.foundation_member_data_access_object import FoundationMemberDAO from rfai.dao.request_data_access_object import RequestDAO from rfai.dao.solution_data_access_object import SolutionDAO from rfai.dao.stake_data_access_object import StakeDAO from rfai.dao.vote_data_access_object import VoteDAO from rfai.dao.rfai_request_repository import RFAIRequestRepository from rfai.rfai_status import RFAIStatusCodes import json from common.logger import get_logger obj_utils = Utils() obj_blockchain_utils = BlockChainUtil(provider_type="HTTP_PROVIDER", provider=NETWORK["http_provider"]) logger = get_logger(__name__) class RFAIService: def __init__(self, repo): self.request_dao = RequestDAO(repo=repo) self.vote_dao = VoteDAO(repo=repo) self.solution_dao = SolutionDAO(repo=repo) self.stake_dao = StakeDAO(repo=repo) self.foundation_member_dao = FoundationMemberDAO(repo=repo) self.rfai_request_dao = RFAIRequestRepository(repo=repo) def _format_filter_params(self, query_parameters): filter_params = {} # if "requester" in query_parameters.keys():
def __init__(self, net_id, ws_provider, ipfs_url, ipfs_port): self._ipfs_util = IPFSUtil(ipfs_url, ipfs_port) self._blockchain_util = BlockChainUtil("WS_PROVIDER", ws_provider) self._net_id = net_id