def bulk_payout_job(body=None): # noqa: E501 """Performs a payout to multiple ethereum addresses. When the payout happens, final results are uploaded to S3 and contract's state is updated to Partial or Paid depending on contract's balance. :param body: :type body: dict | bytes :rtype: BoolDataResponse """ if connexion.request.is_json: body = BulkPayoutJobBody.from_dict( connexion.request.get_json()) # noqa: E501 try: factory_addr = launcher(get_escrow(body.address), body.gas_payer) except Exception as e: return ErrorNotexistResponse(str(e)), 404 try: req = Request(body.results_url) req.add_header( "User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36" ) req.add_header("X-Requested-With", "XMLHttpRequest") data = urlopen(req).read() results = json.loads(data) except Exception as e: return ErrorParameterResponse(str(e), "results_url"), 400 try: req = Request(body.payouts_url) req.add_header( "User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36" ) req.add_header("X-Requested-With", "XMLHttpRequest") data = urlopen(req).read() payouts = [(address, Decimal(amount)) for (address, amount) in json.loads(data).items()] except Exception as e: return ErrorParameterResponse(str(e), "payouts_url"), 400 try: job = Job(credentials={ "gas_payer": body.gas_payer, "gas_payer_priv": body.gas_payer_private, "rep_oracle_priv_key": bytes(body.gas_payer_private.lstrip("0x"), encoding="utf-8") }, factory_addr=factory_addr, escrow_addr=body.address) except Exception as e: return ErrorUnauthorizedResponse(str(e)), 401 try: return BoolDataResponse( job.bulk_payout(payouts, results, bytes(body.rep_oracle_pub, encoding="utf-8"))), 200 except Exception as e: return ErrorParameterResponse(str(e), "rep_oracle_pub_key"), 400
def complete_job(address, gas_payer, gas_payer_private): # noqa: E501 """Complete a given job Complete a given job # noqa: E501 :param address: Deployed Job address :type address: str :param gas_payer: address paying which started the job or a trusted handler :type gas_payer: str :param gas_payer_private: Private Key for the address paying for the gas costs :type gas_payer_private: str :rtype: BoolDataResponse """ try: factory_addr = launcher(get_escrow(address), gas_payer) except Exception as e: return ErrorNotexistResponse(str(e)), 404 try: job = Job(credentials={ "gas_payer": gas_payer, "gas_payer_priv": gas_payer_private, "rep_oracle_priv_key": bytes(gas_payer_private.lstrip("0x"), encoding="utf-8") }, factory_addr=factory_addr, escrow_addr=address) return BoolDataResponse(job.complete()), 200 except Exception as e: return ErrorUnauthorizedResponse(str(e)), 401
def add_job_trusted_handlers(body=None): # noqa: E501 """Add trusted handlers that can freely transact with the contract A trusted handler can perform aborts and cancels, for example :param body: :type body: dict | bytes :rtype: BoolDataResponse """ if connexion.request.is_json: body = AddJobTrustedHandlersBody.from_dict( connexion.request.get_json()) # noqa: E501 try: factory_addr = launcher(get_escrow(body.address), body.gas_payer) except Exception as e: return ErrorNotexistResponse(str(e)), 404 try: job = Job(credentials={ "gas_payer": body.gas_payer, "gas_payer_priv": body.gas_payer_private, "rep_oracle_priv_key": bytes(body.gas_payer_private.lstrip("0x"), encoding="utf-8") }, factory_addr=factory_addr, escrow_addr=body.address) except Exception as e: return ErrorUnauthorizedResponse(str(e)), 401 try: return BoolDataResponse(job.add_trusted_handlers( body.handlers)), 200 except Exception as e: return ErrorParameterResponse(str(e), "handlers"), 400
def get_job_balanace(address, gas_payer, gas_payer_private): # noqa: E501 """Balance in HMT of a given job address Balance in HMT of a given job address # noqa: E501 :param address: Deployed Job address :type address: str :param gas_payer: address paying for the gas costs :type gas_payer: str :param gas_payer_private: Private Key for the address paying for the gas costs :type gas_payer_private: str :rtype: IntDataResponse """ try: factory_addr = launcher(get_escrow(address), gas_payer) job = Job(credentials={ "gas_payer": gas_payer, "gas_payer_priv": gas_payer_private, "rep_oracle_priv_key": bytes(gas_payer_private.lstrip("0x"), encoding="utf-8") }, factory_addr=factory_addr, escrow_addr=address) return IntDataResponse(job.balance()), 200 except Exception as e: return ErrorNotexistResponse(str(e)), 404
def store_job_intermediate_results(body=None): # noqa: E501 """Store intermediate results to S3 for the given escrow Given an escrow address, a URL where the results can be found in the form of a JSON file, and a public key will upload to S3 these intermediate results and will emit an event on the escrow contract # noqa: E501 :param body: :type body: dict | bytes :rtype: BoolDataResponse """ if connexion.request.is_json: body = StoreJobIntermediateResultsBody.from_dict( connexion.request.get_json()) # noqa: E501 try: factory_addr = launcher(get_escrow(body.address), body.gas_payer) except Exception as e: return ErrorNotexistResponse(str(e)), 404 try: req = Request(body.results_url) req.add_header( "User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36" ) req.add_header("X-Requested-With", "XMLHttpRequest") data = urlopen(req).read() results = json.loads(data) except Exception as e: return ErrorParameterResponse(str(e), "results_url"), 400 try: job = Job(credentials={ "gas_payer": body.gas_payer, "gas_payer_priv": body.gas_payer_private, "rep_oracle_priv_key": bytes(body.gas_payer_private.lstrip("0x"), encoding="utf-8") }, factory_addr=factory_addr, escrow_addr=body.address) except Exception as e: return ErrorUnauthorizedResponse(str(e)), 401 try: return BoolDataResponse( job.store_intermediate_results( results, bytes(body.rep_oracle_pub, encoding="utf-8"))), 200 except Exception as e: return ErrorParameterResponse(str(e), "rep_oracle_pub_key"), 400
def get_job_status(address, gas_payer, gas_payer_private): # noqa: E501 """Status of a given job address Receive the status of a given job address # noqa: E501 :param address: Deployed Job address :type address: str :param gas_payer: address paying for the gas costs :type gas_payer: str :param gas_payer_private: Private Key for the address paying for the gas costs :type gas_payer_private: str :rtype: JobStatusResponse """ try: return JobStatusResponse(str(status(get_escrow(address), gas_payer))), 200 except Exception as e: return ErrorNotexistResponse(str(e)), 404
def get_job_manifest_url(address, gas_payer, gas_payer_private): # noqa: E501 """Manifest URL of a given job address Receive the Manifest URL of a given job address # noqa: E501 :param address: Deployed Job address :type address: str :param gas_payer: address paying for the gas costs :type gas_payer: str :param gas_payer_private: Private Key for the address paying for the gas costs :type gas_payer_private: str :rtype: StringDataResponse """ try: return StringDataResponse(manifest_url(get_escrow(address), gas_payer)), 200 except Exception as e: return ErrorNotexistResponse(str(e)), 404
def _access_job(self, factory_addr: str, escrow_addr: str, **credentials): """Given a factory and escrow address and credentials, access an already launched manifest of an already deployed escrow contract. Args: factory_addr (str): an ethereum address of the escrow factory contract. escrow_addr (str): an ethereum address of the escrow contract. **credentials: an unpacked dict of an ethereum address and its private key. """ gas_payer = credentials["gas_payer"] rep_oracle_priv_key = credentials["rep_oracle_priv_key"] self.factory_contract = get_factory(factory_addr) self.job_contract = get_escrow(escrow_addr) self.manifest_url = manifest_url(self.job_contract, gas_payer) self.manifest_hash = manifest_hash(self.job_contract, gas_payer) manifest_dict = self.manifest(rep_oracle_priv_key) escrow_manifest = Manifest(manifest_dict) self._init_job(escrow_manifest)
def launch(self, pub_key: bytes) -> bool: """Launches an escrow contract to the network, uploads the manifest to IPFS with the public key of the Reputation Oracle and stores the IPFS url to the escrow contract. Args: pub_key (bytes): the public key of the Reputation Oracle. Returns: bool: returns True if Job initialization and Ethereum and IPFS transactions succeed. >>> credentials = { ... "gas_payer": "0x1413862C2B7054CDbfdc181B83962CB0FC11fD92", ... "gas_payer_priv": "28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5" ... } >>> rep_oracle_pub_key = b"2dbc2c2c86052702e7c219339514b2e8bd4687ba1236c478ad41b43330b08488c12c8c1797aa181f3a4596a1bd8a0c18344ea44d6655f61fa73e56e743f79e0d" >>> job = Job(credentials, manifest) Deploying a new Job to the ethereum network succeeds. >>> job.launch(rep_oracle_pub_key) True >>> job.status() <Status.Launched: 1> """ if hasattr(self, "job_contract"): raise AttributeError("The escrow has been already deployed.") # Use factory to deploy a new escrow contract. self._create_escrow() job_addr = self._last_escrow_addr() LOG.info("Job's escrow contract deployed to:{}".format(job_addr)) self.job_contract = get_escrow(job_addr) # Upload the manifest to IPFS. (hash_, manifest_url) = upload(self.serialized_manifest, pub_key) self.manifest_url = manifest_url self.manifest_hash = hash_ return self.status() == Status.Launched and self.balance() == 0
def job_final_results(address, gas_payer, gas_payer_private, rep_oracle_private): # noqa: E501 """Retrieve the final results Retrieve the final results # noqa: E501 :param address: Deployed Job address :type address: str :param gas_payer: address paying which started the job or a trusted handler :type gas_payer: str :param gas_payer_private: Private Key for the address paying for the gas costs :type gas_payer_private: str :param rep_oracle_private: Private Key for the reputation oracle :type rep_oracle_private: str :rtype: StringDataResponse """ try: factory_addr = launcher(get_escrow(address), gas_payer) except Exception as e: return ErrorNotexistResponse(str(e)), 404 try: job = Job(credentials={ "gas_payer": gas_payer, "gas_payer_priv": gas_payer_private, "rep_oracle_priv_key": bytes(rep_oracle_private, encoding="utf-8") }, factory_addr=factory_addr, escrow_addr=address) return StringDataResponse( json.dumps( job.final_results(bytes(rep_oracle_private, encoding="utf-8")))), 200 except Exception as e: return ErrorUnauthorizedResponse(str(e)), 401
def test_get_escrow(self): self.job.launch(self.rep_oracle_pub_key) self.assertIsNotNone(get_escrow(self.job.job_contract.address))