Exemplo n.º 1
0
    def setUpClass(cls):
        log = logging.getLogger("NodeRpcTest")
        log.debug("Setting up NodeRpcTest")

        DOTENV_FILE = '.env.test'
        env_config = Config(RepositoryEnv(DOTENV_FILE))

        cls.network = env_config('NETWORK')
        cls.ela_to_use = env_config('ELA_TO_USE')
        cls.ela_eth_to_use = env_config('ELA_ETH_TO_USE')
        cls.did_to_use = env_config('DID_TO_USE')
        cls.api_key_to_use = get_api_from_did(cls.did_to_use)
        cls.private_key_to_use = env_config('PRIVATE_KEY_TO_USE')
Exemplo n.º 2
0
    def RpcMethod(self, request, context):

        metadata = dict(context.invocation_metadata())
        did = metadata["did"]
        api_key = get_api_from_did(did)

        try:
            jwt_info = jwt.decode(request.input, key=api_key, algorithms=['HS256']).get('jwt_info')
        except Exception as e:
            status_message = 'Authentication Error'
            logging.debug(f"RpcMethod : {did} : {api_key} : {status_message} : {e}")
            return node_rpc_pb2.Response(output='', status_message=status_message, status=False)

        if type(jwt_info) == str:
            jwt_info = json.loads(jwt_info)

        # Check whether the user is able to use this API by checking their rate limiter
        response = self.rate_limiter.check_rate_limit(settings.NODE_RPC_LIMIT, api_key,
                                                      self.RpcMethod.__name__)
        if response:
            status_message = f'Number of daily access limit exceeded {response["result"]["daily_limit"]}'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return node_rpc_pb2.Response(output=json.dumps(response),
                                         status_message=status_message,
                                         status=False)

        network = jwt_info['network']
        chain = jwt_info["chain"]
        method = jwt_info["method"]
        params = jwt_info["params"]

        d = {"method": method}
        if params:
            d["params"] = params
        if chain == "mainchain" and not (
                method in settings.NODE_COMMON_RPC_METHODS or method in settings.NODE_MAIN_RPC_METHODS):
            status_message = f'The method {method} is not available for the chain {chain}'
            logging.debug(f"{api_key} : {status_message}")
            return node_rpc_pb2.Response(output=json.dumps({}),
                                         status_message=status_message,
                                         status=False)

        if chain != "mainchain" and chain != "eth" and method not in settings.NODE_COMMON_RPC_METHODS:
            status_message = f'The method {method} is not available for the chain {chain}'
            logging.debug(f"{api_key} : {status_message}")
            return node_rpc_pb2.Response(output=json.dumps({}),
                                         status_message=status_message,
                                         status=False)

        if chain == "eth" and method not in settings.NODE_SIDECHAIN_ETH_RPC_METHODS:
            status_message = f'The method {method} is not available for the chain {chain}'
            logging.debug(f"{api_key} : {status_message}")
            return node_rpc_pb2.Response(output=json.dumps({}),
                                         status_message=status_message,
                                         status=False)

        if network == "mainnet":
            if chain == "mainchain":
                url = config('MAIN_NET_MAINCHAIN_RPC_PORT')
            elif chain == "did":
                url = config('MAIN_NET_SIDECHAIN_DID_RPC_PORT')
            elif chain == "token":
                url = config('MAIN_NET_SIDECHAIN_TOKEN_RPC_PORT')
            elif chain == "eth":
                url = config('MAIN_NET_SIDECHAIN_ETH_RPC_PORT')
                d["id"] = 1
            else:
                status_message = f'The chain {chain} is not supported for the network {network}'
                logging.debug(f"{api_key} : {status_message}")
                return node_rpc_pb2.Response(output=json.dumps({}),
                                             status_message=status_message,
                                             status=False)
        else:
            if chain == "mainchain":
                url = config('PRIVATE_NET_MAINCHAIN_RPC_PORT')
            elif chain == "did":
                url = config('PRIVATE_NET_SIDECHAIN_DID_RPC_PORT')
            elif chain == "token":
                url = config('PRIVATE_NET_SIDECHAIN_TOKEN_RPC_PORT')
            elif chain == "eth":
                url = config('PRIVATE_NET_SIDECHAIN_ETH_RPC_PORT')
                d["id"] = 1
            else:
                status_message = f'The chain {chain} is not supported for the network {network}'
                logging.debug(f"{api_key} : {status_message}")
                return node_rpc_pb2.Response(output=json.dumps({}),
                                             status_message=status_message,
                                             status=False)

        response = requests.post(url, data=json.dumps(d), headers=self.headers, timeout=REQUEST_TIMEOUT)
        data = json.loads(response.text)

        # generate jwt token
        jwt_info = {
            'result': data['result']
        }

        jwt_token = jwt.encode({
            'jwt_info': jwt_info,
            'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=settings.TOKEN_EXPIRATION)
        }, api_key, algorithm='HS256')

        return node_rpc_pb2.Response(output=jwt_token,
                                     status_message=f'Successfully called the method {method} for the chain {chain} in network {network}',
                                     status=True)
    def UploadAndSign(self, request, context):

        metadata = dict(context.invocation_metadata())
        did = metadata["did"]
        api_key = get_api_from_did(did)

        try:
            jwt_info = jwt.decode(request.input,
                                  key=api_key,
                                  algorithms=['HS256']).get('jwt_info')
        except Exception as e:
            status_message = 'Authentication Error'
            logging.debug(
                f"UploadAndSign : {did} : {api_key} : {status_message} : {e}")
            return hive_pb2.Response(output='',
                                     status_message=status_message,
                                     status=False)

        # reading input data
        if type(jwt_info) == str:
            # request from go package
            jwt_info = json.loads(jwt_info)

        network = jwt_info['network']
        private_key = jwt_info['privateKey']
        file_content = request.file_content

        # Check whether the user is able to use this API by checking their rate limiter
        response = self.rate_limiter.check_rate_limit(
            settings.UPLOAD_AND_SIGN_LIMIT, api_key,
            self.UploadAndSign.__name__)
        if response:
            status_message = f'Number of daily access limit exceeded {response["result"]["daily_limit"]}'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return hive_pb2.Response(output=json.dumps(response),
                                     status_message=status_message,
                                     status=False)

        # checking file size
        if sys.getsizeof(file_content) > settings.FILE_UPLOAD_SIZE_LIMIT:
            status_message = "File size limit exceeded"
            logging.debug(f"{did} : {api_key} : {status_message}")
            return hive_pb2.Response(output="",
                                     status_message=status_message,
                                     status=False)

        if network == "mainnet":
            did_api_url = config(
                'MAIN_NET_DID_SERVICE_URL') + settings.DID_SERVICE_API_SIGN
            hive_api_url = config(
                'MAIN_NET_HIVE_PORT') + settings.HIVE_API_ADD_FILE
        else:
            did_api_url = config(
                'PRIVATE_NET_DID_SERVICE_URL') + settings.DID_SERVICE_API_SIGN
            hive_api_url = config(
                'PRIVATE_NET_HIVE_PORT') + settings.HIVE_API_ADD_FILE

        # encoding and encrypting
        key = get_encrypt_key(private_key)
        fernet = Fernet(key)
        file_content_encrypted = fernet.encrypt(file_content)

        # upload file to hive
        response = requests.get(hive_api_url,
                                files={'file': file_content_encrypted},
                                headers=self.headers['hive'],
                                timeout=REQUEST_TIMEOUT)
        data = json.loads(response.text)
        file_hash = data['Hash']

        if not data:
            status_message = 'Error: File could not be uploaded'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return hive_pb2.Response(output="",
                                     status_message=status_message,
                                     status=False)

        # signing the hash key
        req_data = {"privateKey": private_key, "msg": file_hash}
        response = requests.post(did_api_url,
                                 data=json.dumps(req_data),
                                 headers=self.headers['general'],
                                 timeout=REQUEST_TIMEOUT)
        data = json.loads(response.text)
        data['result']['hash'] = file_hash

        if data['status'] == 200:
            status_message = 'Successfully uploaded file to Elastos Hive'
            status = True
        else:
            status_message = 'Error'
            status = False

        del data['status']

        # generate jwt token
        jwt_info = {'result': data['result']}

        jwt_token = jwt.encode(
            {
                'jwt_info':
                jwt_info,
                'exp':
                datetime.datetime.utcnow() +
                datetime.timedelta(hours=settings.TOKEN_EXPIRATION)
            },
            api_key,
            algorithm='HS256')

        return hive_pb2.Response(output=jwt_token,
                                 status_message=status_message,
                                 status=status)
    def VerifyAndShow(self, request, context):

        metadata = dict(context.invocation_metadata())
        did = metadata["did"]
        api_key = get_api_from_did(did)

        try:
            jwt_info = jwt.decode(request.input,
                                  key=api_key,
                                  algorithms=['HS256']).get('jwt_info')
        except Exception as e:
            status_message = 'Authentication Error'
            logging.debug(
                f"VerifyAndShow : {did} : {api_key} : {status_message} : {e}")
            return hive_pb2.Response(output='',
                                     status_message=status_message,
                                     status=False)

        if type(jwt_info) == str:
            jwt_info = json.loads(jwt_info)

        network = jwt_info['network']
        signed_message = jwt_info['msg']
        public_key = jwt_info['pub']
        message_signature = jwt_info['sig']
        message_hash = jwt_info['hash']
        private_key = jwt_info['privateKey']

        # Check whether the user is able to use this API by checking their rate limiter
        response = self.rate_limiter.check_rate_limit(
            settings.VERIFY_AND_SHOW_LIMIT, api_key,
            self.VerifyAndShow.__name__)
        if response:
            status_message = f'Number of daily access limit exceeded {response["result"]["daily_limit"]}'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return hive_pb2.Response(output=json.dumps(response),
                                     status_message=status_message,
                                     status=False)

        if network == "mainnet":
            did_api_sign_url = config(
                'MAIN_NET_DID_SERVICE_URL') + settings.DID_SERVICE_API_SIGN
            did_api_verify_url = config(
                'MAIN_NET_DID_SERVICE_URL') + settings.DID_SERVICE_API_VERIFY
            hive_api_url = config(
                'MAIN_NET_HIVE_PORT') + settings.HIVE_API_RETRIEVE_FILE + "{}"
        else:
            did_api_sign_url = config(
                'PRIVATE_NET_DID_SERVICE_URL') + settings.DID_SERVICE_API_SIGN
            did_api_verify_url = config('PRIVATE_NET_DID_SERVICE_URL'
                                        ) + settings.DID_SERVICE_API_VERIFY
            hive_api_url = config('PRIVATE_NET_HIVE_PORT'
                                  ) + settings.HIVE_API_RETRIEVE_FILE + "{}"

        # verify the hash key
        json_data = {
            "msg": signed_message,
            "pub": public_key,
            "sig": message_signature
        }
        response = requests.post(did_api_verify_url,
                                 data=json.dumps(json_data),
                                 headers=self.headers['general'],
                                 timeout=REQUEST_TIMEOUT)
        data = json.loads(response.text)
        if not data['result']:
            return hive_pb2.Response(
                output="",
                status_message='Hash key could not be verified',
                status=False)

        # verify the given input message using private key
        req_data = {"privateKey": private_key, "msg": message_hash}
        response = requests.post(did_api_sign_url,
                                 data=json.dumps(req_data),
                                 headers=self.headers['general'],
                                 timeout=REQUEST_TIMEOUT)
        data = json.loads(response.text)
        if data['status'] != 200:
            status_message = 'Hash Key and message could not be verified'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return hive_pb2.Response(output="",
                                     status_message=status_message,
                                     status=False)

        if data['result']['msg'] != signed_message:
            status_message = 'Hash Key and message could not be verified'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return hive_pb2.Response(output="",
                                     status_message=status_message,
                                     status=False)

        # show content
        response = requests.get(hive_api_url.format(jwt_info['hash']),
                                headers=self.headers['general'],
                                timeout=REQUEST_TIMEOUT)

        # decrypt message
        key = get_encrypt_key(private_key)
        fernet = Fernet(key)
        decrypted_message = fernet.decrypt(response.text.encode())

        # generate jwt token
        jwt_info = {}

        jwt_token = jwt.encode(
            {
                'jwt_info':
                jwt_info,
                'exp':
                datetime.datetime.utcnow() +
                datetime.timedelta(hours=settings.TOKEN_EXPIRATION)
            },
            api_key,
            algorithm='HS256')

        return hive_pb2.Response(
            output=jwt_token,
            file_content=decrypted_message,
            status_message='Successfully retrieved file from Elastos Hive',
            status=True)
    def CreateWallet(self, request, context):

        metadata = dict(context.invocation_metadata())
        did = metadata["did"]
        api_key = get_api_from_did(did)

        try:
            jwt_info = jwt.decode(request.input,
                                  key=api_key,
                                  algorithms=['HS256']).get('jwt_info')
        except Exception as e:
            status_message = 'Authentication Error'
            logging.debug(
                f"CreateWallet : {did} : {api_key} : {status_message} : {e}")
            return wallet_pb2.Response(output='',
                                       status_message=status_message,
                                       status=False)

        if type(jwt_info) == str:
            jwt_info = json.loads(jwt_info)

        network = jwt_info['network']

        # Check whether the user is able to use this API by checking their rate limiter
        response = self.rate_limiter.check_rate_limit(
            settings.CREATE_WALLET_LIMIT, api_key, self.CreateWallet.__name__)
        if response:
            status_message = f'Number of daily access limit exceeded {response["result"]["daily_limit"]}'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return wallet_pb2.Response(output=json.dumps(response),
                                       status_message=status_message,
                                       status=False)

        # Create wallets
        wallet_mainchain = create_wallet_mainchain(self.headers, network)
        if wallet_mainchain is None:
            status_message = 'Error: Mainchain wallet could not created'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return wallet_pb2.Response(output="",
                                       status_message=status_message,
                                       status=False)

        wallet_sidechain_did = create_wallet_sidechain_did(
            self.headers, network)
        if wallet_sidechain_did is None:
            status_message = 'Error: DID Sidechain wallet could not created'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return wallet_pb2.Response(output="",
                                       status_message=status_message,
                                       status=False)

        wallet_sidechain_token = wallet_mainchain

        wallet_sidechain_eth = create_wallet_sidechain_eth(network)
        if wallet_sidechain_eth is None:
            status_message = 'Error: Eth Sidechain wallet could not created'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return wallet_pb2.Response(output="",
                                       status_message=status_message,
                                       status=False)

        # generate jwt token
        jwt_info = {
            'result': {
                'mainchain': {
                    'mnemonic': wallet_mainchain['mnemonic'],
                    'private_key': wallet_mainchain['private_key'],
                    'public_key': wallet_mainchain['public_key'],
                    'address': wallet_mainchain['address']
                },
                'sidechain': {
                    'did': {
                        'mnemonic': wallet_sidechain_did['mnemonic'],
                        'private_key': wallet_sidechain_did['private_key'],
                        'public_key': wallet_sidechain_did['public_key'],
                        'address': wallet_sidechain_did['address'],
                        'did': wallet_sidechain_did['did'],
                    },
                    'token': {
                        'mnemonic': wallet_sidechain_token['mnemonic'],
                        'private_key': wallet_sidechain_token['private_key'],
                        'public_key': wallet_sidechain_token['public_key'],
                        'address': wallet_sidechain_token['address'],
                    },
                    'eth': {
                        'address': wallet_sidechain_eth['address'],
                        'private_key': wallet_sidechain_eth['private_key']
                    }
                },
            }
        }

        jwt_token = jwt.encode(
            {
                'jwt_info':
                jwt_info,
                'exp':
                datetime.datetime.utcnow() +
                datetime.timedelta(hours=settings.TOKEN_EXPIRATION)
            },
            api_key,
            algorithm='HS256')

        return wallet_pb2.Response(
            output=jwt_token,
            status_message='Successfully created wallets',
            status=True)
    def RequestELA(self, request, context):

        metadata = dict(context.invocation_metadata())
        did = metadata["did"]
        api_key = get_api_from_did(did)

        try:
            jwt_info = jwt.decode(request.input,
                                  key=api_key,
                                  algorithms=['HS256']).get('jwt_info')
        except Exception as e:
            status_message = 'Authentication Error'
            logging.debug(
                f"RequestELA : {did} : {api_key} : {status_message} : {e}")
            return wallet_pb2.Response(output='',
                                       status_message=status_message,
                                       status=False)

        # Check whether the user is able to use this API by checking their rate limiter
        response = self.rate_limiter.check_rate_limit(
            settings.REQUEST_ELA_LIMIT, api_key, self.RequestELA.__name__)
        if response:
            status_message = f'Number of daily access limit exceeded {response["result"]["daily_limit"]}'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return wallet_pb2.Response(output=json.dumps(response),
                                       status_message=status_message,
                                       status=False)

        if type(jwt_info) == str:
            jwt_info = json.loads(jwt_info)

        chain = jwt_info['chain']
        address = jwt_info['address']

        status_message = 'Successfully deposited ELA. Please wait 2-4 minutes for the ELA to arrive on main chain and ' \
                         '12-15 minutes to arrive on PoW sidechains'
        status = True
        amount = 5
        if chain == "eth":
            currency_representation = "ELAETHSC"
            if len(WalletAddressesETH) < 10000:
                WalletAddressesETH.add(address)
            else:
                status_message = "Could not deposit ELA at this time. Please try again later"
                status = False
        else:
            if len(WalletAddresses) < 10000:
                WalletAddresses.add((chain, address))
            else:
                status_message = "Could not deposit ELA at this time. Please try again later"
                status = False
            if chain == "mainchain":
                amount = 10
                currency_representation = "ELA"
            if chain == "did":
                currency_representation = "ELADIDSC"
            elif chain == "token":
                currency_representation = "ELATOKENSC"

        # generate jwt token
        jwt_info = {
            'result': {
                'address': address,
                'deposit_amount': "{0} {1}".format(amount,
                                                   currency_representation)
            }
        }

        jwt_token = jwt.encode(
            {
                'jwt_info':
                jwt_info,
                'exp':
                datetime.datetime.utcnow() +
                datetime.timedelta(hours=settings.TOKEN_EXPIRATION)
            },
            api_key,
            algorithm='HS256')

        return wallet_pb2.Response(output=jwt_token,
                                   status_message=status_message,
                                   status=status)
Exemplo n.º 7
0
    def DeployEthContract(self, request, context):

        metadata = dict(context.invocation_metadata())
        did = metadata["did"]
        api_key = get_api_from_did(did)

        try:
            jwt_info = jwt.decode(request.input,
                                  key=api_key,
                                  algorithms=['HS256']).get('jwt_info')
        except Exception as e:
            status_message = 'Authentication Error'
            logging.debug(
                f"DeployEthContract : {did} : {api_key} : {status_message} : {e}"
            )
            return sidechain_eth_pb2.Response(output='',
                                              status_message=status_message,
                                              status=False)

        if type(jwt_info) == str:
            jwt_info = json.loads(jwt_info)

        network = jwt_info['network']

        # Check whether the user is able to use this API by checking their rate limiter
        response = self.rate_limiter.check_rate_limit(
            settings.DEPLOY_ETH_CONTRACT_LIMIT, api_key,
            self.DeployEthContract.__name__)
        if response:
            status_message = f'Number of daily access limit exceeded {response["result"]["daily_limit"]}'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return sidechain_eth_pb2.Response(output=json.dumps(response),
                                              status_message=status_message,
                                              status=False)

        if network == "mainnet":
            hive_api_url = config(
                'MAIN_NET_HIVE_PORT') + settings.HIVE_API_ADD_FILE
            web3 = Web3(
                HTTPProvider(config('MAIN_NET_SIDECHAIN_ETH_RPC_PORT'),
                             request_kwargs={'timeout': 60}))
        else:
            hive_api_url = config(
                'PRIVATE_NET_HIVE_PORT') + settings.HIVE_API_ADD_FILE
            web3 = Web3(
                HTTPProvider(config('PRIVATE_NET_SIDECHAIN_ETH_RPC_PORT'),
                             request_kwargs={'timeout': 60}))

        # reading the file content
        eth_account_address = jwt_info['eth_account_address']
        eth_gas = jwt_info['eth_gas']
        eth_private_key = jwt_info['eth_private_key']
        contract_name = jwt_info['contract_name']
        contract_source = jwt_info['contract_source']

        # upload smart contract code to hive
        response = requests.get(hive_api_url,
                                headers=self.headers,
                                files={'file': contract_source},
                                timeout=REQUEST_TIMEOUT)
        data = json.loads(response.text)
        hive_hash = data['Hash']

        if not response:
            status_message = 'Error: Smart contract code could not be uploaded'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return sidechain_eth_pb2.Response(output="",
                                              status_message=status_message,
                                              status=False)

        try:
            # We need this since our eth sidechain is POA
            web3.middleware_onion.inject(geth_poa_middleware, layer=0)
            if not web3.isConnected():
                status_message = 'Error: Could not connect to Eth Sidechain node'
                logging.debug(f"{did} : {api_key} : {status_message}")
                return sidechain_eth_pb2.Response(
                    output="", status_message=status_message, status=False)

            compiled_sol = compile_standard({
                "language": "Solidity",
                "sources": {
                    contract_name: {
                        "content": contract_source,
                    },
                },
                "settings": {
                    'evmVersion': 'byzantium',
                    "outputSelection": {
                        "*": {
                            "*": ["*"]
                        }
                    }
                }
            })

            # get bytecode
            bytecode = compiled_sol['contracts'][contract_name][contract_name][
                'evm']['bytecode']['object']

            transaction = {
                'gas':
                eth_gas,
                'gasPrice':
                web3.eth.gasPrice,
                'nonce':
                web3.eth.getTransactionCount(
                    web3.toChecksumAddress(eth_account_address)),
                'data':
                '0x' + bytecode
            }
            signed_tx = web3.eth.account.sign_transaction(
                transaction, eth_private_key)
            if signed_tx is None:
                status_message = 'Error: Transaction could not be signed'
                logging.debug(f"{did} : {api_key} : {status_message}")
                return sidechain_eth_pb2.Response(
                    output="", status_message=status_message, status=False)

            # Submit the transaction that deploys the contract
            tx_hash = web3.eth.sendRawTransaction(signed_tx.rawTransaction)
            if tx_hash is None:
                status_message = 'Error: Transaction could not be send to deploy contract'
                logging.debug(f"{did} : {api_key} : {status_message}")
                return sidechain_eth_pb2.Response(
                    output="", status_message=status_message, status=False)

            # Wait for the transaction to be mined, and get the transaction receipt
            tx_receipt = web3.eth.waitForTransactionReceipt(tx_hash)
        except Exception as e:
            status_message = 'Error Occurred while deploying the Ethereum Contract'
            logging.debug(
                f"DeployEthContract : {did} : {api_key} : {status_message} : {e}"
            )
            return sidechain_eth_pb2.Response(output='',
                                              status_message=status_message,
                                              status=False)

        # generate jwt token
        jwt_info = {
            'result': {
                'contract_address': tx_receipt.contractAddress,
                'contract_name': contract_name,
                'contract_code_hash': hive_hash,
            }
        }

        jwt_token = jwt.encode(
            {
                'jwt_info':
                jwt_info,
                'exp':
                datetime.datetime.utcnow() +
                datetime.timedelta(hours=settings.TOKEN_EXPIRATION)
            },
            api_key,
            algorithm='HS256')

        return sidechain_eth_pb2.Response(
            output=jwt_token,
            status_message='Successfully deployed Eth Smart Contract',
            status=True)
Exemplo n.º 8
0
    def WatchEthContract(self, request, context):

        metadata = dict(context.invocation_metadata())
        did = metadata["did"]
        api_key = get_api_from_did(did)

        try:
            jwt_info = jwt.decode(request.input,
                                  key=api_key,
                                  algorithms=['HS256']).get('jwt_info')
        except Exception as e:
            status_message = 'Authentication Error'
            logging.debug(
                f"WatchEthContract : {did} : {api_key} : {status_message} : {e}"
            )
            return sidechain_eth_pb2.Response(output='',
                                              status_message=status_message,
                                              status=False)

        if type(jwt_info) == str:
            jwt_info = json.loads(jwt_info)

        network = jwt_info['network']

        # Check whether the user is able to use this API by checking their rate limiter
        response = self.rate_limiter.check_rate_limit(
            settings.WATCH_ETH_CONTRACT_LIMIT, api_key,
            self.WatchEthContract.__name__)
        if response:
            status_message = f'Number of daily access limit exceeded {response["result"]["daily_limit"]}'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return sidechain_eth_pb2.Response(output=json.dumps(response),
                                              status_message=status_message,
                                              status=False)

        if network == "mainnet":
            hive_api_url = config(
                'MAIN_NET_HIVE_PORT') + settings.HIVE_API_RETRIEVE_FILE + "{}"
            web3 = Web3(
                HTTPProvider(config('MAIN_NET_SIDECHAIN_ETH_RPC_PORT'),
                             request_kwargs={'timeout': 60}))
        else:
            hive_api_url = config('PRIVATE_NET_HIVE_PORT'
                                  ) + settings.HIVE_API_RETRIEVE_FILE + "{}"
            web3 = Web3(
                HTTPProvider(config('PRIVATE_NET_SIDECHAIN_ETH_RPC_PORT'),
                             request_kwargs={'timeout': 60}))

        # reading the file content
        contract_address = jwt_info['contract_address']
        contract_name = jwt_info['contract_name']
        contract_code_hash = jwt_info['contract_code_hash']

        # show smart contract code from Hive
        response = requests.get(hive_api_url.format(contract_code_hash),
                                headers=self.headers,
                                timeout=REQUEST_TIMEOUT)
        contract_source = response.text

        if not response:
            status_message = 'Error: Smart contract code could not be retrieved from Hive'
            logging.debug(f"{did} : {api_key} : {status_message}")
            return sidechain_eth_pb2.Response(output="",
                                              status_message=status_message,
                                              status=False)

        try:
            # Get smart contract details
            compiled_sol = compile_standard({
                "language": "Solidity",
                "sources": {
                    contract_name: {
                        "content": contract_source,
                    },
                },
                "settings": {
                    'evmVersion': 'byzantium',
                    "outputSelection": {
                        "*": {
                            "*": ["*"]
                        }
                    }
                }
            })
            abi = json.loads(compiled_sol['contracts'][contract_name]
                             [contract_name]['metadata'])['output']['abi']

            # We need this since our eth sidechain is POA
            web3.middleware_onion.inject(geth_poa_middleware, layer=0)

            contract = web3.eth.contract(address=contract_address, abi=abi)
            functions = contract.all_functions()
            contract_functions = []
            for function in functions:
                contract_function = repr(function)[1:-1].split()[1]
                contract_functions.append(contract_function)
        except Exception as e:
            status_message = 'Error Occurred while watching the Ethereum Contract'
            logging.debug(
                f"WatchEthContract : {did} : {api_key} : {status_message} : {e}"
            )
            return sidechain_eth_pb2.Response(output='',
                                              status_message=status_message,
                                              status=False)

        # generate jwt token
        jwt_info = {
            'result': {
                'contract_address': contract_address,
                'contract_functions': contract_functions,
                'contract_source': contract_source
            }
        }

        jwt_token = jwt.encode(
            {
                'jwt_info':
                jwt_info,
                'exp':
                datetime.datetime.utcnow() +
                datetime.timedelta(hours=settings.TOKEN_EXPIRATION)
            },
            api_key,
            algorithm='HS256')

        return sidechain_eth_pb2.Response(
            output=jwt_token,
            status_message='Successfully viewed Eth Smart Contract',
            status=True)