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 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 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 setUp(self): self.credentials = { "gas_payer": "0x1413862C2B7054CDbfdc181B83962CB0FC11fD92", "gas_payer_priv": "28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5", } self.rep_oracle_pub_key = b"2dbc2c2c86052702e7c219339514b2e8bd4687ba1236c478ad41b43330b08488c12c8c1797aa181f3a4596a1bd8a0c18344ea44d6655f61fa73e56e743f79e0d" self.job = Job(self.credentials, manifest)
def test_job_bulk_payout(self): self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) payouts = [ ("0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", Decimal("20.0")), ("0x852023fbb19050B8291a335E5A83Ac9701E7B4E6", Decimal("50.0")), ] self.assertTrue( self.job.bulk_payout(payouts, {}, self.rep_oracle_pub_key)) # The escrow contract is still in Partial state as there's still balance left. self.assertEqual(self.job.balance(), 30000000000000000000) self.assertEqual(self.job.status(), Status(3)) # Trying to pay more than the contract balance results in failure. payouts = [("0x9d689b8f50Fd2CAec716Cc5220bEd66E03F07B5f", Decimal("40.0"))] self.assertFalse( self.job.bulk_payout(payouts, {}, self.rep_oracle_pub_key)) # Paying the remaining amount empties the escrow and updates the status correctly. payouts = [("0x9d689b8f50Fd2CAec716Cc5220bEd66E03F07B5f", Decimal("30.0"))] self.assertTrue( self.job.bulk_payout(payouts, {}, self.rep_oracle_pub_key)) self.assertEqual(self.job.balance(), 0) self.assertEqual(self.job.status(), Status(4)) multi_credentials = [ ( "0x61F9F0B31eacB420553da8BCC59DC617279731Ac", "486a0621e595dd7fcbe5608cbbeec8f5a8b5cabe7637f11eccfc7acd408c3a0e", ), ( "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", "f22d4fc42da79aa5ba839998a0a9f2c2c45f5e55ee7f1504e464d2c71ca199e1", ), ] self.job = Job(self.credentials, manifest, multi_credentials=multi_credentials) self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) payouts = [ ("0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", Decimal("20.0")), ("0x852023fbb19050B8291a335E5A83Ac9701E7B4E6", Decimal("50.0")), ] self.assertTrue( self.job.bulk_payout(payouts, {}, self.rep_oracle_pub_key))
def test_complete_job(self): """Test case for complete_job Complete a given job """ with open(f"{PAYOUTS_PATH}", "r") as payouts_file: data = payouts_file.read() payouts = [(address, Decimal(amount)) for (address, amount) in json.loads(data).items()] job = Job({ "gas_payer": GAS_PAYER, "gas_payer_priv": GAS_PAYER_PRIV }, manifest, FACTORY_ADDRESS) job.launch(REP_ORACLE_PUB_KEY) job.setup() job.bulk_payout(payouts, {}, REP_ORACLE_PUB_KEY) query_string = [('address', job.job_contract.address), ('gasPayer', GAS_PAYER), ('gasPayerPrivate', GAS_PAYER_PRIV)] response = self.client.open('/job/complete', method='GET', query_string=query_string) self.assert200(response, 'Response body is: ' + response.data.decode('utf-8')) self.assertTrue( json.loads(response.data.decode('utf-8')).get("success", False))
def test_download(self): credentials = { "gas_payer": "0x1413862C2B7054CDbfdc181B83962CB0FC11fD92", "gas_payer_priv": "28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5", } pub_key = b"2dbc2c2c86052702e7c219339514b2e8bd4687ba1236c478ad41b43330b08488c12c8c1797aa181f3a4596a1bd8a0c18344ea44d6655f61fa73e56e743f79e0d" job = Job(credentials=credentials, escrow_manifest=manifest) (_, manifest_url) = upload(job.serialized_manifest, pub_key) manifest_dict = download(manifest_url, job.gas_payer_priv) self.assertEqual(manifest_dict, job.serialized_manifest) job = Job(credentials=credentials, escrow_manifest=manifest) (_, manifest_url) = upload(job.serialized_manifest, pub_key) manifest_dict = download(manifest_url, job.gas_payer_priv) self.assertEqual(manifest_dict, job.serialized_manifest)
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 test_get_job_status(self): """Test case for get_job_status Status of a given job address """ job = Job({ "gas_payer": GAS_PAYER, "gas_payer_priv": GAS_PAYER_PRIV }, manifest, FACTORY_ADDRESS) job.launch(REP_ORACLE_PUB_KEY) query_string = [('address', job.job_contract.address), ('gasPayer', GAS_PAYER), ('gasPayerPrivate', GAS_PAYER_PRIV)] response = self.client.open('/job/status', method='GET', query_string=query_string) self.assert200(response, 'Response body is: ' + response.data.decode('utf-8'))
def test_job_setup(self): # A Job can't be setup without deploying it first. self.assertFalse(self.job.setup()) multi_credentials = [ ( "0x61F9F0B31eacB420553da8BCC59DC617279731Ac", "28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5", ), ( "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", "f22d4fc42da79aa5ba839998a0a9f2c2c45f5e55ee7f1504e464d2c71ca199e1", ), ] self.job = Job(self.credentials, manifest, multi_credentials=multi_credentials) self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup())
def test_job_launch(self): self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertEqual(self.job.status(), Status(1)) multi_credentials = [ ( "0x61F9F0B31eacB420553da8BCC59DC617279731Ac", "486a0621e595dd7fcbe5608cbbeec8f5a8b5cabe7637f11eccfc7acd408c3a0e", ), ( "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", "f22d4fc42da79aa5ba839998a0a9f2c2c45f5e55ee7f1504e464d2c71ca199e1", ), ] self.job = Job(self.credentials, manifest, multi_credentials=multi_credentials) # Inject wrong credentials on purpose to test out raffling self.job.gas_payer_priv = ( "657b6497a355a3982928d5515d48a84870f057c4d16923eb1d104c0afada9aa8") self.job.multi_credentials = [ ( "0x61F9F0B31eacB420553da8BCC59DC617279731Ac", "28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5", ), ( "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", "f22d4fc42da79aa5ba839998a0a9f2c2c45f5e55ee7f1504e464d2c71ca199e1", ), ] self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertEqual(self.job.status(), Status(1)) # Make sure we launched with raffled credentials self.assertEqual(self.job.gas_payer, "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809") self.assertEqual( self.job.gas_payer_priv, "f22d4fc42da79aa5ba839998a0a9f2c2c45f5e55ee7f1504e464d2c71ca199e1", )
def test_ipns(self, mocked_ipfs_client, _): """ Test storage: upload, download, create_new_ipns_link, etc """ credentials = { "gas_payer": "0x1413862C2B7054CDbfdc181B83962CB0FC11fD92", "gas_payer_priv": "28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5" } pub_key = b"2dbc2c2c86052702e7c219339514b2e8bd4687ba1236c478ad41b43330b08488c12c8c1797aa181f3a4596a1bd8a0c18344ea44d6655f61fa73e56e743f79e0d" job = Job(credentials=credentials, escrow_manifest=Manifest({ 'task_bid_price': 9, 'request_type': 'image_label_binary', 'job_total_tasks': 10 })) name = 'abc' mocked_ipfs_client.key.list.side_effect = MI.key_list mocked_ipfs_client.key.gen.side_effect = MI.key_gen mocked_ipfs_client.name.publish.side_effect = MI.publish mocked_ipfs_client.add_bytes.side_effect = MI.add_bytes mocked_ipfs_client.resolve.side_effect = MI.resolve mocked_ipfs_client.cat.side_effect = MI.cat ipns_id = create_new_ipns_link(name) # Upload 1 (hash_, manifest_url) = upload(job.serialized_manifest, pub_key, name) manifest_dict = download(ipns_id, job.gas_payer_priv) dl_equals_up = manifest_dict == job.serialized_manifest link_exist = ipns_link_exists(name) ipns_urls_match = ipns_id == get_ipns_link(name).split('/')[-1] self.assertTrue(dl_equals_up) self.assertTrue(link_exist) self.assertTrue(ipns_urls_match) # Upload 2 data2 = dict( Manifest({ 'task_bid_price': 999999, 'request_type': 'image_label_binary', 'job_total_tasks': 30010 }).serialize()) (hash_, manifest_url) = upload(data2, pub_key, name) manifest_dict = download(ipns_id, job.gas_payer_priv) dl_equals_up = manifest_dict == data2 link_exist = ipns_link_exists(name) ipns_urls_match = ipns_id == get_ipns_link(name).split('/')[-1] self.assertTrue(dl_equals_up) self.assertTrue(link_exist) self.assertTrue(ipns_urls_match)
def test_add_job_trusted_handlers(self): """Test case for add_job_trusted_handlers Add trusted handlers that can freely transact with the contract """ trusted_handlers = [ '0x61F9F0B31eacB420553da8BCC59DC617279731Ac', '0xD979105297fB0eee83F7433fC09279cb5B94fFC6' ] job = Job({ "gas_payer": GAS_PAYER, "gas_payer_priv": GAS_PAYER_PRIV }, manifest, FACTORY_ADDRESS) job.launch(REP_ORACLE_PUB_KEY) job.setup() body = AddJobTrustedHandlersBody(GAS_PAYER, GAS_PAYER_PRIV, job.job_contract.address, trusted_handlers) response = self.client.open('/job/addTrustedHandlers', method='POST', data=json.dumps(body), content_type='application/json') self.assert200(response, 'Response body is: ' + response.data.decode('utf-8')) self.assertTrue( json.loads(response.data.decode('utf-8')).get("success", False))
def test_bulk_payout_job(self): """Test case for bulk_payout_job Performs a payout to multiple ethereum addresses. """ results_url = f"file://{RESULTS_PATH}" payouts_url = f"file://{PAYOUTS_PATH}" job = Job({ "gas_payer": GAS_PAYER, "gas_payer_priv": GAS_PAYER_PRIV }, manifest, FACTORY_ADDRESS) job.launch(REP_ORACLE_PUB_KEY) job.setup() body = BulkPayoutJobBody(GAS_PAYER, GAS_PAYER_PRIV, job.job_contract.address, REP_ORACLE_PUB_KEY.decode("utf-8"), results_url, payouts_url) response = self.client.open('/job/bulkPayout', method='POST', data=json.dumps(body), content_type='application/json') self.assert200(response, 'Response body is: ' + response.data.decode('utf-8')) self.assertTrue( json.loads(response.data.decode('utf-8')).get("success", False))
def create_job(manifest: Optional[Manifest] = None, gas_payer: Optional[str] = None, gas_payer_priv: Optional[str] = None) -> Job: """ Creates sample Job instance """ manifest = manifest or sample_manifest credentials = { "gas_payer": gas_payer or "0x1413862C2B7054CDbfdc181B83962CB0FC11fD92", "gas_payer_priv": gas_payer_priv or "28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5", } return Job(credentials=credentials, escrow_manifest=manifest)
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_job_abort(self): """ The escrow contract is in Paid state after the full bulk payout, and it can't be aborted. """ self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) payouts = [("0x852023fbb19050B8291a335E5A83Ac9701E7B4E6", Decimal("100.0"))] self.assertTrue( self.job.bulk_payout(payouts, {"results": 0}, self.rep_oracle_pub_key)) self.assertFalse(self.job.abort()) self.assertEqual(self.job.status(), Status(4)) # Trusted handler should be able to abort an existing contract self.job = Job(self.credentials, manifest) self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) trusted_handler = "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809" self.assertTrue(self.job.add_trusted_handlers([trusted_handler])) handler_credentials = { "gas_payer": "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", "gas_payer_priv": "f22d4fc42da79aa5ba839998a0a9f2c2c45f5e55ee7f1504e464d2c71ca199e1", "rep_oracle_priv_key": b"28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5", } access_job = Job( credentials=handler_credentials, factory_addr=self.job.factory_contract.address, escrow_addr=self.job.job_contract.address, ) self.assertTrue(access_job.abort())
def test_job_bulk_payout_with_encryption_option(self): """Tests whether final results must be persisted in storage encrypted or plain. """ job = Job(self.credentials, manifest) self.assertEqual(job.launch(self.rep_oracle_pub_key), True) self.assertEqual(job.setup(), True) payouts = [("0x852023fbb19050B8291a335E5A83Ac9701E7B4E6", Decimal("100.0"))] final_results = {'results': 0} mock_upload = MagicMock(return_value=('hash', 'url')) # Testing option as: do not encrypt final results: encrypt_final_results=False with patch('hmt_escrow.job.upload', mock_upload): # Bulk payout with final results as plain (not encrypted) job.bulk_payout(payouts=payouts, results=final_results, pub_key=self.rep_oracle_pub_key, encrypt_final_results=False) mock_upload.assert_called_once_with( msg=final_results, public_key=self.rep_oracle_pub_key, encrypt_data=False) mock_upload.reset_mock() # Testing option as: encrypt final results: encrypt_final_results=True with patch("hmt_escrow.job.upload", mock_upload): # Bulk payout with final results as plain (not encrypted) job.bulk_payout(payouts=payouts, results={"results": 0}, pub_key=self.rep_oracle_pub_key, encrypt_final_results=True) mock_upload.assert_called_once_with( msg=final_results, public_key=self.rep_oracle_pub_key, encrypt_data=True)
def test_intermediate_results_job(self): """Test case for intermediate_results_job Retrieve the intermediate results stored by the Recording Oracle """ job = Job({ "gas_payer": GAS_PAYER, "gas_payer_priv": GAS_PAYER_PRIV }, manifest, FACTORY_ADDRESS) job.launch(REP_ORACLE_PUB_KEY) job.setup() job.store_intermediate_results({"results": True}, REP_ORACLE_PUB_KEY) query_string = [('address', job.job_contract.address), ('gasPayer', GAS_PAYER), ('gasPayerPrivate', GAS_PAYER_PRIV), ('repOraclePrivate', GAS_PAYER_PRIV.lstrip("0x"))] response = self.client.open('/job/intermediateResults', method='GET', query_string=query_string) self.assert200(response, 'Response body is: ' + response.data.decode('utf-8'))
def test_final_results_job(self): """Test case for final_results_job Retrieve the final results stored by the Recording Oracle """ job = Job({ "gas_payer": GAS_PAYER, "gas_payer_priv": GAS_PAYER_PRIV }, manifest, FACTORY_ADDRESS) job.launch(REP_ORACLE_PUB_KEY) job.setup() payouts = [("0x852023fbb19050B8291a335E5A83Ac9701E7B4E6", Decimal('100.0'))] job.bulk_payout(payouts, {'results': 0}, REP_ORACLE_PUB_KEY) query_string = [('address', job.job_contract.address), ('gasPayer', GAS_PAYER), ('gasPayerPrivate', GAS_PAYER_PRIV), ('repOraclePrivate', GAS_PAYER_PRIV.lstrip("0x"))] response = self.client.open('/job/finalResults', method='GET', query_string=query_string) self.assert200(response, 'Response body is: ' + response.data.decode('utf-8'))
def test_store_job_intermediate_results_job(self): """Test case for store_job_intermediate_results_job Store intermediate results to S3 for the given escrow """ results_url = f"file://{RESULTS_PATH}" job = Job({ "gas_payer": GAS_PAYER, "gas_payer_priv": GAS_PAYER_PRIV }, manifest, FACTORY_ADDRESS) job.launch(REP_ORACLE_PUB_KEY) job.setup() body = StoreJobIntermediateResultsBody( GAS_PAYER, GAS_PAYER_PRIV, job.job_contract.address, REP_ORACLE_PUB_KEY.decode("utf-8"), results_url) response = self.client.open('/job/storeIntermediateResults', method='POST', data=json.dumps(body), content_type='application/json') self.assert200(response, 'Response body is: ' + response.data.decode('utf-8')) self.assertTrue( json.loads(response.data.decode('utf-8')).get("success", False))
def test_job_init(self): # Creating a new Job instance initializes the critical attributes correctly. self.assertEqual(self.job.gas_payer, self.credentials["gas_payer"]) self.assertEqual(self.job.gas_payer_priv, self.credentials["gas_payer_priv"]) self.assertEqual(self.job.serialized_manifest["oracle_stake"], "0.05") self.assertEqual(self.job.amount, Decimal("100.0")) # Initializing a new Job instance with a factory address succeeds. factory_addr = deploy_factory(**(self.credentials)) self.job = Job(self.credentials, manifest, factory_addr) self.assertTrue(self.job.factory_contract.address, factory_addr) self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) self.assertTrue( launcher(self.job.job_contract, self.credentials["gas_payer"]).lower(), self.job.factory_contract.address.lower(), ) # Initializing an existing Job instance with a factory and escrow address succeeds. self.credentials[ "rep_oracle_priv_key"] = b"28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5" escrow_addr = self.job.job_contract.address factory_addr = self.job.factory_contract.address manifest_url = self.job.manifest_url new_job = Job( credentials=self.credentials, factory_addr=factory_addr, escrow_addr=escrow_addr, ) self.assertEqual(new_job.manifest_url, manifest_url) self.assertEqual(new_job.job_contract.address, escrow_addr) self.assertEqual(new_job.factory_contract.address, factory_addr) with self.assertRaises(AttributeError): new_job.launch(self.rep_oracle_pub_key)
def new_job(body=None): # noqa: E501 """Creates a new Job and returns the address Creates a new job and returns the address # noqa: E501 :param body: :type body: dict | bytes :rtype: StringDataResponse """ if connexion.request.is_json: body = JobCreateBody.from_dict( connexion.request.get_json()) # noqa: E501 try: req = Request(body.manifest_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() manifest = json.loads(data) job = Job( { "gas_payer": body.gas_payer, "gas_payer_priv": body.gas_payer_private }, Manifest(manifest), body.factory_address) except Exception as e: return ErrorParameterResponse( str(e), "manifest_url or gas_payer_private"), 401 try: job.launch(bytes(body.rep_oracle_pub, encoding="utf-8")) job.setup() return StringDataResponse(job.job_contract.address), 200 except Exception as e: return ErrorParameterResponse(str(e), "rep_oracle_pub_key"), 401
class JobTestCase(unittest.TestCase): def setUp(self): self.credentials = { "gas_payer": "0x1413862C2B7054CDbfdc181B83962CB0FC11fD92", "gas_payer_priv": "28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5", } self.rep_oracle_pub_key = b"2dbc2c2c86052702e7c219339514b2e8bd4687ba1236c478ad41b43330b08488c12c8c1797aa181f3a4596a1bd8a0c18344ea44d6655f61fa73e56e743f79e0d" self.job = Job(self.credentials, manifest) def test_lauch(self): """ Tests job launch """ lauched = self.job.launch(self.rep_oracle_pub_key) self.assertEqual(lauched, True) next_status = status(self.job.job_contract, self.job.gas_payer) self.assertEqual(next_status, Status.Launched) def test_status(self): lauched = self.job.launch(self.rep_oracle_pub_key) self.assertEqual(lauched, True) next_status = status(self.job.job_contract, self.job.gas_payer) self.assertEqual(next_status, Status.Launched) def test_manifest_url(self): self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) self.assertEqual( manifest_hash(self.job.job_contract, self.job.gas_payer), self.job.manifest_hash, ) def test_job_init(self): # Creating a new Job instance initializes the critical attributes correctly. self.assertEqual(self.job.gas_payer, self.credentials["gas_payer"]) self.assertEqual(self.job.gas_payer_priv, self.credentials["gas_payer_priv"]) self.assertEqual(self.job.serialized_manifest["oracle_stake"], "0.05") self.assertEqual(self.job.amount, Decimal("100.0")) # Initializing a new Job instance with a factory address succeeds. factory_addr = deploy_factory(**(self.credentials)) self.job = Job(self.credentials, manifest, factory_addr) self.assertTrue(self.job.factory_contract.address, factory_addr) self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) self.assertTrue( launcher(self.job.job_contract, self.credentials["gas_payer"]).lower(), self.job.factory_contract.address.lower(), ) # Initializing an existing Job instance with a factory and escrow address succeeds. self.credentials[ "rep_oracle_priv_key"] = b"28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5" escrow_addr = self.job.job_contract.address factory_addr = self.job.factory_contract.address manifest_url = self.job.manifest_url new_job = Job( credentials=self.credentials, factory_addr=factory_addr, escrow_addr=escrow_addr, ) self.assertEqual(new_job.manifest_url, manifest_url) self.assertEqual(new_job.job_contract.address, escrow_addr) self.assertEqual(new_job.factory_contract.address, factory_addr) with self.assertRaises(AttributeError): new_job.launch(self.rep_oracle_pub_key) def test_job_launch(self): self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertEqual(self.job.status(), Status(1)) multi_credentials = [ ( "0x61F9F0B31eacB420553da8BCC59DC617279731Ac", "486a0621e595dd7fcbe5608cbbeec8f5a8b5cabe7637f11eccfc7acd408c3a0e", ), ( "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", "f22d4fc42da79aa5ba839998a0a9f2c2c45f5e55ee7f1504e464d2c71ca199e1", ), ] self.job = Job(self.credentials, manifest, multi_credentials=multi_credentials) # Inject wrong credentials on purpose to test out raffling self.job.gas_payer_priv = ( "657b6497a355a3982928d5515d48a84870f057c4d16923eb1d104c0afada9aa8") self.job.multi_credentials = [ ( "0x61F9F0B31eacB420553da8BCC59DC617279731Ac", "28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5", ), ( "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", "f22d4fc42da79aa5ba839998a0a9f2c2c45f5e55ee7f1504e464d2c71ca199e1", ), ] self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertEqual(self.job.status(), Status(1)) # Make sure we launched with raffled credentials self.assertEqual(self.job.gas_payer, "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809") self.assertEqual( self.job.gas_payer_priv, "f22d4fc42da79aa5ba839998a0a9f2c2c45f5e55ee7f1504e464d2c71ca199e1", ) def test_job_setup(self): # A Job can't be setup without deploying it first. self.assertFalse(self.job.setup()) multi_credentials = [ ( "0x61F9F0B31eacB420553da8BCC59DC617279731Ac", "28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5", ), ( "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", "f22d4fc42da79aa5ba839998a0a9f2c2c45f5e55ee7f1504e464d2c71ca199e1", ), ] self.job = Job(self.credentials, manifest, multi_credentials=multi_credentials) self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) def test_job_add_trusted_handlers(self): # Make sure we se set our gas payer as a trusted handler by default. self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue( is_trusted_handler(self.job.job_contract, self.job.gas_payer, self.job.gas_payer)) trusted_handlers = [ "0x61F9F0B31eacB420553da8BCC59DC617279731Ac", "0xD979105297fB0eee83F7433fC09279cb5B94fFC6", ] self.assertTrue(self.job.add_trusted_handlers(trusted_handlers)) self.assertTrue( is_trusted_handler( self.job.job_contract, "0x61F9F0B31eacB420553da8BCC59DC617279731Ac", self.job.gas_payer, )) self.assertTrue( is_trusted_handler( self.job.job_contract, "0xD979105297fB0eee83F7433fC09279cb5B94fFC6", self.job.gas_payer, )) def test_job_bulk_payout(self): self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) payouts = [ ("0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", Decimal("20.0")), ("0x852023fbb19050B8291a335E5A83Ac9701E7B4E6", Decimal("50.0")), ] self.assertTrue( self.job.bulk_payout(payouts, {}, self.rep_oracle_pub_key)) # The escrow contract is still in Partial state as there's still balance left. self.assertEqual(self.job.balance(), 30000000000000000000) self.assertEqual(self.job.status(), Status(3)) # Trying to pay more than the contract balance results in failure. payouts = [("0x9d689b8f50Fd2CAec716Cc5220bEd66E03F07B5f", Decimal("40.0"))] self.assertFalse( self.job.bulk_payout(payouts, {}, self.rep_oracle_pub_key)) # Paying the remaining amount empties the escrow and updates the status correctly. payouts = [("0x9d689b8f50Fd2CAec716Cc5220bEd66E03F07B5f", Decimal("30.0"))] self.assertTrue( self.job.bulk_payout(payouts, {}, self.rep_oracle_pub_key)) self.assertEqual(self.job.balance(), 0) self.assertEqual(self.job.status(), Status(4)) multi_credentials = [ ( "0x61F9F0B31eacB420553da8BCC59DC617279731Ac", "486a0621e595dd7fcbe5608cbbeec8f5a8b5cabe7637f11eccfc7acd408c3a0e", ), ( "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", "f22d4fc42da79aa5ba839998a0a9f2c2c45f5e55ee7f1504e464d2c71ca199e1", ), ] self.job = Job(self.credentials, manifest, multi_credentials=multi_credentials) self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) payouts = [ ("0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", Decimal("20.0")), ("0x852023fbb19050B8291a335E5A83Ac9701E7B4E6", Decimal("50.0")), ] self.assertTrue( self.job.bulk_payout(payouts, {}, self.rep_oracle_pub_key)) def test_job_bulk_payout_with_encryption_option(self): """Tests whether final results must be persisted in storage encrypted or plain. """ job = Job(self.credentials, manifest) self.assertEqual(job.launch(self.rep_oracle_pub_key), True) self.assertEqual(job.setup(), True) payouts = [("0x852023fbb19050B8291a335E5A83Ac9701E7B4E6", Decimal("100.0"))] final_results = {'results': 0} mock_upload = MagicMock(return_value=('hash', 'url')) # Testing option as: do not encrypt final results: encrypt_final_results=False with patch('hmt_escrow.job.upload', mock_upload): # Bulk payout with final results as plain (not encrypted) job.bulk_payout(payouts=payouts, results=final_results, pub_key=self.rep_oracle_pub_key, encrypt_final_results=False) mock_upload.assert_called_once_with( msg=final_results, public_key=self.rep_oracle_pub_key, encrypt_data=False) mock_upload.reset_mock() # Testing option as: encrypt final results: encrypt_final_results=True with patch("hmt_escrow.job.upload", mock_upload): # Bulk payout with final results as plain (not encrypted) job.bulk_payout(payouts=payouts, results={"results": 0}, pub_key=self.rep_oracle_pub_key, encrypt_final_results=True) mock_upload.assert_called_once_with( msg=final_results, public_key=self.rep_oracle_pub_key, encrypt_data=True) def test_job_abort(self): """ The escrow contract is in Paid state after the full bulk payout, and it can't be aborted. """ self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) payouts = [("0x852023fbb19050B8291a335E5A83Ac9701E7B4E6", Decimal("100.0"))] self.assertTrue( self.job.bulk_payout(payouts, {"results": 0}, self.rep_oracle_pub_key)) self.assertFalse(self.job.abort()) self.assertEqual(self.job.status(), Status(4)) # Trusted handler should be able to abort an existing contract self.job = Job(self.credentials, manifest) self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) trusted_handler = "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809" self.assertTrue(self.job.add_trusted_handlers([trusted_handler])) handler_credentials = { "gas_payer": "0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", "gas_payer_priv": "f22d4fc42da79aa5ba839998a0a9f2c2c45f5e55ee7f1504e464d2c71ca199e1", "rep_oracle_priv_key": b"28e516f1e2f99e96a48a23cea1f94ee5f073403a1c68e818263f0eb898f1c8e5", } access_job = Job( credentials=handler_credentials, factory_addr=self.job.factory_contract.address, escrow_addr=self.job.job_contract.address, ) self.assertTrue(access_job.abort()) def test_job_cancel(self): self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) payouts = [("0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809", Decimal("20.0"))] self.assertTrue( self.job.bulk_payout(payouts, {}, self.rep_oracle_pub_key)) self.assertEqual(self.job.status(), Status(3)) # The escrow contract is in Paid state after the second payout and it can't be cancelled. payouts = [("0x852023fbb19050B8291a335E5A83Ac9701E7B4E6", Decimal("80.0"))] self.assertTrue( self.job.bulk_payout(payouts, {"results": 0}, self.rep_oracle_pub_key)) self.assertFalse(self.job.cancel()) self.assertEqual(self.job.status(), Status(4)) def test_job_status(self): self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertEqual(self.job.status(), Status(1)) def test_job_balance(self): self.assertTrue(self.job.launch(self.rep_oracle_pub_key)) self.assertTrue(self.job.setup()) self.assertEqual(self.job.balance(), 100000000000000000000) def test_launch_failure(self): """ Test _launch raises error on failure to create contract """ handler_mock = MagicMock() handler_mock.side_effect = Exception("") e = None with self.assertRaises(Exception) as e: with patch("hmt_escrow.eth_bridge.handle_transaction", handler_mock): self.job.launch(b"") self.assertIsNotNone(e) self.assertEqual(str(e.exception), "Unable to create escrow") def test__raffle_txn_retry(self): """ Test general retry logic """ retries = 4 delay = 0.01 backoff = 2 self.job.retry = Retry(retries=retries, delay=delay, backoff=backoff) txn_mock = MagicMock() handler_mock = MagicMock(side_effect=Exception) sleep_mock = MagicMock() with patch("hmt_escrow.eth_bridge.handle_transaction", handler_mock), patch("hmt_escrow.eth_bridge.sleep", sleep_mock): success = self.job._raffle_txn( multi_creds=[("1", "11")], txn_func=txn_mock, txn_args=[], txn_event="Transfer", ) self.assertFalse(success) self.assertEqual( handler_mock.call_args_list, [ call(txn_mock, gas_payer="1", gas_payer_priv="11", gas=6700000) for i in range(5) ], ) self.assertEqual( sleep_mock.call_args_list, [call(delay * backoff**i) for i in range(retries)], ) sleep_mock.reset_mock() handler_mock.reset_mock() handler_mock.side_effect = Exception # no retries self.job.retry = Retry() success = self.job._raffle_txn( multi_creds=[("1", "11")], txn_func=txn_mock, txn_args=[], txn_event="Transfer", ) self.assertFalse(success) self.assertEqual( handler_mock.call_args_list, [ call(txn_mock, gas_payer="1", gas_payer_priv="11", gas=6700000) ], ) self.assertEqual(sleep_mock.call_args_list, []) def test_get_hmt_balance(self): """ Test wallet HMT balance is OK """ amount = utils.get_hmt_balance( "0x1413862C2B7054CDbfdc181B83962CB0FC11fD92", "0x56B532F1D090E4edb1c92F30d3087771AE6B6992", get_w3(), ) print(amount) self.assertGreater(amount, 10000)