def add_payment(self, payment_info): """ Add new payment to the database. :param payment_info: """ Payment.create(subtask=payment_info.subtask_id, payee=payment_info.computer.eth_account.address, value=payment_info.value)
def test_payment_big_value(self): value = 10000 * 10**18 assert value > 2**64 Payment.create(payee="me", subtask="T1000", value=value, status=PaymentStatus.sent)
def test_invalid_value_type(self): with self.assertRaises(TypeError): Payment.create(payee="XX", subtask="float", value=5.5, status=PaymentStatus.sent) with self.assertRaises(TypeError): Payment.create(payee="XX", subtask="str", value="500", status=PaymentStatus.sent)
def test_failed_transaction(self): balance_eth = 1 * denoms.ether balance_gntb = 99 * denoms.ether self.sci.get_eth_balance.return_value = balance_eth self.sci.get_gntb_balance.return_value = balance_gntb gnt_value = 10**17 p = Payment.create(subtask="p1", payee=urandom(20), value=gnt_value) self.pp.add(p) self.pp.CLOSURE_TIME_DELAY = 0 tx_hash = '0xdead' self.sci.batch_transfer.return_value = tx_hash assert self.pp.sendout(0) tx_block_number = 1337 receipt = TransactionReceipt({ 'transactionHash': HexBytes(tx_hash), 'blockNumber': tx_block_number, 'blockHash': HexBytes('0x' + 64 * 'f'), 'gasUsed': 55001, 'status': 0, }) with mock.patch('golem.ethereum.paymentprocessor.threads') as threads: self.sci.on_transaction_confirmed.call_args[0][1](receipt) threads.deferToThread.assert_called_once_with( self.pp._on_batch_confirmed, [p], receipt, ) self.pp._on_batch_confirmed([p], receipt) self.assertEqual(p.status, PaymentStatus.awaiting) assert len(self.pp._awaiting) == 1
def test_single_payment(self, *_): self.pp._run() self.gnt.create(sender=self.privkey) self.state.mine() self.check_synchronized() assert self.pp.gnt_balance() == 1000 * denoms.ether payee = urandom(20) b = self.pp.gnt_balance() # FIXME: Big values does not fit into the database value = random.randint(0, b / 1000) p1 = Payment.create(subtask="p1", payee=payee, value=value) assert self.pp._gnt_available() == b assert self.pp._gnt_reserved() == 0 self.pp.add(p1) assert self.pp._gnt_available() == b - value assert self.pp._gnt_reserved() == value # Sendout. self.pp.deadline = int(time.time()) self.pp._run() assert self.pp.gnt_balance(True) == b - value assert self.pp._gnt_available() == b - value assert self.pp._gnt_reserved() == 0 assert self.gnt.balanceOf(payee) == value assert self.gnt.balanceOf(tester.a1) == self.pp._gnt_available() # Confirm. assert self.pp.gnt_balance(True) == b - value assert self.pp._gnt_reserved() == 0
def test_load_from_db_sent(self): tx_hash1 = encode_hex(urandom(32)) tx_hash2 = encode_hex(urandom(32)) value = 10 payee = urandom(20) sent_payment11 = Payment.create( subtask=str(uuid.uuid4()), payee=payee, value=value, details=PaymentDetails(tx=tx_hash1[2:]), status=PaymentStatus.sent) sent_payment12 = Payment.create( subtask=str(uuid.uuid4()), payee=payee, value=value, details=PaymentDetails(tx=tx_hash1[2:]), status=PaymentStatus.sent) sent_payment21 = Payment.create( subtask=str(uuid.uuid4()), payee=payee, value=value, details=PaymentDetails(tx=tx_hash2[2:]), status=PaymentStatus.sent) self.pp.load_from_db() self.assertEqual(3 * value, self.pp.reserved_gntb) self.assertEqual(0, self.pp.recipients_count) assert self.sci.on_transaction_confirmed.call_count == 2 assert self.sci.on_transaction_confirmed.call_args_list[0][0][0] == \ tx_hash1 assert self.sci.on_transaction_confirmed.call_args_list[1][0][0] == \ tx_hash2 with mock.patch('golem.ethereum.paymentprocessor.threads') as threads: self.sci.on_transaction_confirmed.call_args_list[0][0][1]( mock.Mock()) threads.deferToThread.assert_called_once_with( self.pp._on_batch_confirmed, [sent_payment11, sent_payment12], mock.ANY, ) threads.reset_mock() self.sci.on_transaction_confirmed.call_args_list[1][0][1]( mock.Mock()) threads.deferToThread.assert_called_once_with( self.pp._on_batch_confirmed, [sent_payment21], mock.ANY, )
def test_no_gnt_available(self): self.pp.start() self.gnt.create(sender=self.privkey) self.state.mine() self.check_synchronized() assert self.pp.gnt_balance() == 1000 * denoms.ether payee = urandom(20) b = self.pp.gnt_balance() value = b / 5 - 100 for i in range(5): subtask_id = 's{}'.format(i) p = Payment.create(subtask=subtask_id, payee=payee, value=value) assert self.pp.add(p) q = Payment.create(subtask='F', payee=payee, value=value) assert not self.pp.add(q)
def test_add_failure(self): a1 = urandom(20) a2 = urandom(20) p1 = Payment.create(subtask="p1", payee=a1, value=1) p2 = Payment.create(subtask="p2", payee=a2, value=2) assert p1.status is PaymentStatus.awaiting assert p2.status is PaymentStatus.awaiting self.client.get_balance.return_value = 0 assert self.pp.add(p1) is False assert self.pp.add(p2) is False self.client.get_balance.assert_called_once_with( '0x' + self.addr.encode('hex')) assert p1.status is PaymentStatus.awaiting assert p2.status is PaymentStatus.awaiting
def test_payment_deadline(self): a1 = urandom(20) a2 = urandom(20) a3 = urandom(20) self.client.get_balance.return_value = 100 * denoms.ether self.client.call.return_value = hex(100 * denoms.ether)[:-1] now = int(time.time()) assert self.pp.add(Payment.create(subtask="p1", payee=a1, value=1)) assert check_deadline(self.pp.deadline, now + self.pp.DEFAULT_DEADLINE) assert self.pp.add(Payment.create(subtask="p2", payee=a2, value=1), deadline=20000) assert check_deadline(self.pp.deadline, now + self.pp.DEFAULT_DEADLINE) assert self.pp.add(Payment.create(subtask="p3", payee=a2, value=1), deadline=1) assert check_deadline(self.pp.deadline, now + 1) assert self.pp.add(Payment.create(subtask="p4", payee=a3, value=1)) assert check_deadline(self.pp.deadline, now + 1) assert self.pp.add(Payment.create(subtask="p5", payee=a3, value=1), deadline=1) assert check_deadline(self.pp.deadline, now + 1) assert self.pp.add(Payment.create(subtask="p6", payee=a3, value=1), deadline=0) assert check_deadline(self.pp.deadline, now) assert self.pp.add(Payment.create(subtask="p7", payee=a3, value=1), deadline=-1) assert check_deadline(self.pp.deadline, now - 1)
def test_add_invalid_payment_status(self): a1 = urandom(20) p1 = Payment.create(subtask="p1", payee=a1, value=1, status=PaymentStatus.confirmed) assert p1.status is PaymentStatus.confirmed with self.assertRaises(RuntimeError): self.pp.add(p1)
def test_payment_timestamp(self): self.sci.get_eth_balance.return_value = denoms.ether ts = 7000000 p = Payment.create(subtask="p1", payee=urandom(20), value=1) with freeze_time(timestamp_to_datetime(ts)): self.pp.add(p) self.assertEqual(ts, p.processed_ts) new_ts = 900000 with freeze_time(timestamp_to_datetime(new_ts)): self.pp.add(p) self.assertEqual(ts, p.processed_ts)
def test_monitor_progress(self): balance_eth = 1 * denoms.ether balance_gntb = 99 * denoms.ether gas_price = 10**9 self.sci.get_eth_balance.return_value = balance_eth self.sci.get_gntb_balance.return_value = balance_gntb self.sci.get_transaction_gas_price.return_value = gas_price self.pp.CLOSURE_TIME_DELAY = 0 assert self.pp.reserved_gntb == 0 assert self.pp.recipients_count == 0 gnt_value = 10**17 p = Payment.create(subtask="p1", payee=urandom(20), value=gnt_value) self.pp.add(p) assert self.pp.reserved_gntb == gnt_value assert self.pp.recipients_count == 1 tx_hash = '0xdead' self.sci.batch_transfer.return_value = tx_hash assert self.pp.sendout(0) assert self.sci.batch_transfer.call_count == 1 self.sci.on_transaction_confirmed.assert_called_once_with( tx_hash, mock.ANY, ) tx_block_number = 1337 self.sci.get_block_number.return_value = tx_block_number receipt = TransactionReceipt({ 'transactionHash': HexBytes(tx_hash), 'blockNumber': tx_block_number, 'blockHash': HexBytes('0x' + 64 * 'f'), 'gasUsed': 55001, 'status': 1, }) with mock.patch('golem.ethereum.paymentprocessor.threads') as threads: self.sci.on_transaction_confirmed.call_args[0][1](receipt) threads.deferToThread.assert_called_once_with( self.pp._on_batch_confirmed, [p], receipt, ) self.pp._on_batch_confirmed([p], receipt) self.assertEqual(p.status, PaymentStatus.confirmed) self.assertEqual(p.details.block_number, tx_block_number) self.assertEqual(p.details.block_hash, 64 * 'f') self.assertEqual(p.details.fee, 55001 * gas_price) self.assertEqual(self.pp.reserved_gntb, 0)
def add_payment_info(self, task_id, subtask_id, value, account_info): """ Add to payment keeper information about new payment for subtask. :param str task_id: ID if a task the payment is related to. :param str subtask_id: the id of the compleated subtask this payment is for. :param int value: Aggreed value of the computed subtask. :param AccountInfo account_info: Billing account. :raise ValueError: In case of incorrect payee address """ payee = account_info.eth_account.address if len(payee) != 20: raise ValueError( "Incorrect 'payee' length: {}. Should be 20".format( len(payee))) return Payment.create(subtask=subtask_id, payee=payee, value=value)
def test_load_from_db_awaiting(self): self.assertEqual([], self.pp._awaiting) value = 10 payment = Payment.create( subtask=str(uuid.uuid4()), payee=urandom(20), value=value, ) self.pp.load_from_db() expected = [payment] self.assertEqual(expected, self.pp._awaiting) self.assertEqual(value, self.pp.reserved_gntb) self.assertLess(0, self.pp.recipients_count)
def test_payment_deadline_not_reached(self): a1 = urandom(20) self.client.get_balance.return_value = 100 * denoms.ether self.client.call.return_value = hex(100 * denoms.ether)[:-1] now = int(time.time()) inf = now + 12 * 30 * 24 * 60 * 60 deadline = self.pp.deadline assert self.pp.deadline > inf assert not self.pp.sendout() assert self.pp.deadline == deadline p = Payment.create(subtask="p1", payee=a1, value=1111) assert self.pp.add(p, deadline=1111) assert check_deadline(self.pp.deadline, now + 1111) assert not self.pp.sendout() assert check_deadline(self.pp.deadline, now + 1111)
def test_create(self): p = Payment(payee="DEF", subtask="xyz", value=5, status=PaymentStatus.awaiting) self.assertEquals(p.save(force_insert=True), 1) with self.assertRaises(IntegrityError): Payment.create(payee="DEF", subtask="xyz", value=5, status=PaymentStatus.awaiting) Payment.create(payee="DEF", subtask="xyz2", value=4, status=PaymentStatus.confirmed) Payment.create(payee="DEF2", subtask="xyz4", value=5, status=PaymentStatus.sent) self.assertEqual(3, len([payment for payment in Payment.select()]))
def test_payment_aggregation(self): a1 = urandom(20) a2 = urandom(20) a3 = urandom(20) self.client.get_balance.return_value = 100 * denoms.ether self.client.call.return_value = hex(100 * denoms.ether)[:-1] assert self.pp.add(Payment.create(subtask="p1", payee=a1, value=1)) assert self.pp.add(Payment.create(subtask="p2", payee=a2, value=1)) assert self.pp.add(Payment.create(subtask="p3", payee=a2, value=1)) assert self.pp.add(Payment.create(subtask="p4", payee=a3, value=1)) assert self.pp.add(Payment.create(subtask="p5", payee=a3, value=1)) assert self.pp.add(Payment.create(subtask="p6", payee=a3, value=1)) self.pp.deadline = int(time.time()) assert self.pp.sendout() assert self.client.send.call_count == 1 tx = self.client.send.call_args[0][0] assert tx.value == 0 assert len( tx.data) == 4 + 2 * 32 + 3 * 32 # Id + array abi + bytes32[3]
def add_payment(subtask_id: str, eth_address: bytes, value: int): """ Add new payment to the database. :param payment_info: """ Payment.create(subtask=subtask_id, payee=eth_address, value=value)
def test_monitor_progress(self): a1 = urandom(20) inprogress = self.pp._inprogress # Give 1 ETH and 99 GNT balance_eth = 1 * denoms.ether balance_gnt = 99 * denoms.ether self.client.get_balance.return_value = balance_eth self.client.call.return_value = hex(balance_gnt)[:-1] # Skip L suffix. assert self.pp._gnt_reserved() == 0 assert self.pp._gnt_available() == balance_gnt assert self.pp._eth_reserved() == 0 assert self.pp._eth_available() == balance_eth gnt_value = 10**17 p = Payment.create(subtask="p1", payee=a1, value=gnt_value) assert self.pp.add(p) assert self.pp._gnt_reserved() == gnt_value assert self.pp._gnt_available() == balance_gnt - gnt_value assert self.pp._eth_reserved( ) == PaymentProcessor.SINGLE_PAYMENT_ETH_COST assert self.pp._eth_available( ) == balance_eth - PaymentProcessor.SINGLE_PAYMENT_ETH_COST self.pp.deadline = int(time.time()) assert self.pp.sendout() assert self.client.send.call_count == 1 tx = self.client.send.call_args[0][0] assert tx.value == 0 assert len(tx.data) == 4 + 2 * 32 + 32 # Id + array abi + bytes32[1] assert len(inprogress) == 1 assert tx.hash in inprogress assert inprogress[tx.hash] == [p] # Check payment status in the Blockchain self.client.get_transaction_receipt.return_value = None self.client.call.return_value = hex(balance_gnt - gnt_value)[:-1] # Skip L suffix. self.pp.monitor_progress() assert len(inprogress) == 1 assert tx.hash in inprogress assert inprogress[tx.hash] == [p] assert self.pp.gnt_balance(True) == balance_gnt - gnt_value assert self.pp._gnt_reserved() == 0 assert self.pp._gnt_available() == balance_gnt - gnt_value assert self.pp._eth_reserved( ) == PaymentProcessor.SINGLE_PAYMENT_ETH_COST assert self.pp._eth_available( ) == balance_eth - PaymentProcessor.SINGLE_PAYMENT_ETH_COST self.pp.monitor_progress() assert len(inprogress) == 1 assert self.pp._gnt_reserved() == 0 assert self.pp._gnt_available() == balance_gnt - gnt_value assert self.pp._eth_reserved( ) == PaymentProcessor.SINGLE_PAYMENT_ETH_COST assert self.pp._eth_available( ) == balance_eth - PaymentProcessor.SINGLE_PAYMENT_ETH_COST receipt = { 'blockNumber': 8214, 'blockHash': '0x' + 64 * 'f', 'gasUsed': 55001 } self.client.get_transaction_receipt.return_value = receipt self.pp.monitor_progress() assert len(inprogress) == 0 assert p.status == PaymentStatus.confirmed assert p.details['block_number'] == 8214 assert p.details['block_hash'] == 64 * 'f' assert p.details['fee'] == 55001 * self.pp.GAS_PRICE assert self.pp._gnt_reserved() == 0
def test_invalid_status(self): with self.assertRaises(TypeError): Payment.create(payee="XX", subtask="zz", value=5, status=1)