def test_errors_from_stellar_tx(self, instruction_index, exp_op_index, exp_payment_index): acc1 = gen_account_id() acc2 = gen_account_id() operations = [ gen_create_op(acc1, acc2), gen_payment_op(acc2, amount=15), gen_payment_op(acc1, amount=15), gen_create_op(acc1, acc2), ] memo = AgoraMemo.new(1, TransactionType.EARN, 1, b'') hash_memo = gen_hash_memo(memo.val) envelope_xdr = gen_tx_envelope_xdr(acc1, 1, operations, hash_memo) env = te.TransactionEnvelope.from_xdr(base64.b64encode(envelope_xdr)) errors = TransactionErrors.from_stellar_tx(env, model_pbv4.TransactionError( reason=model_pbv4.TransactionError.Reason.INSUFFICIENT_FUNDS, instruction_index=instruction_index, ), b'tx_hash') assert isinstance(errors.tx_error, InsufficientBalanceError) assert len(errors.op_errors) == 4 for i in range(0, len(errors.op_errors)): if i == exp_op_index: assert isinstance(errors.op_errors[i], InsufficientBalanceError) else: assert not errors.op_errors[i] if exp_payment_index > -1: assert len(errors.payment_errors) == 2 for i in range(0, len(errors.payment_errors)): if i == exp_payment_index: assert isinstance(errors.payment_errors[i], InsufficientBalanceError) else: assert not errors.payment_errors[i] else: assert not errors.payment_errors
def test_payments_from_envelope(self): acc1 = gen_account_id() acc2 = gen_account_id() acc3 = gen_account_id() operations = [ gen_payment_op(acc2, amount=20), gen_payment_op(acc3, src=acc2, amount=40) ] envelope_xdr = gen_tx_envelope_xdr(acc1, 1, operations, gen_text_memo(b'somememo')) env = te.TransactionEnvelope.from_xdr(base64.b64encode(envelope_xdr)) payments = ReadOnlyPayment.payments_from_envelope(env) assert len(payments) == 2 assert payments[0].sender.raw == acc1.ed25519 assert payments[0].destination.raw == acc2.ed25519 assert payments[0].tx_type == TransactionType.UNKNOWN assert payments[0].quarks == 20 assert not payments[0].invoice assert payments[0].memo == 'somememo' assert payments[1].sender.raw == acc2.ed25519 assert payments[1].destination.raw == acc3.ed25519 assert payments[1].tx_type == TransactionType.UNKNOWN assert payments[1].quarks == 40 assert not payments[1].invoice assert payments[1].memo == 'somememo'
def _generate_envelope(): acc1 = gen_account_id() acc2 = gen_account_id() operations = [gen_payment_op(acc2)] envelope_xdr = gen_tx_envelope_xdr(acc1, 1, operations, gen_text_memo(b'somememo')) return te.TransactionEnvelope.from_xdr(base64.b64encode(envelope_xdr))
def test_from_proto_text_memo(self): op_result = gen_payment_op_result(xdr_const.PAYMENT_UNDERFUNDED) result_xdr = gen_result_xdr(xdr_const.txFAILED, [op_result]) tx_src = gen_account_id() dest = gen_account_id() operations = [gen_payment_op(dest, amount=20)] envelope_xdr = gen_tx_envelope_xdr(tx_src, 1, operations, gen_text_memo(b'somememo')) history_item = tx_pb.HistoryItem( hash=model_pb2.TransactionHash(value=b'somehash'), result_xdr=result_xdr, envelope_xdr=envelope_xdr, cursor=tx_pb.Cursor(value=b'cursor1'), ) data = TransactionData.from_proto(history_item) assert data.tx_hash == b'somehash' assert len(data.payments) == 1 payment = data.payments[0] assert payment.sender.raw == tx_src.ed25519 assert payment.destination.raw == dest.ed25519 assert payment.tx_type == TransactionType.UNKNOWN assert payment.quarks == 20 assert not payment.invoice assert payment.memo == 'somememo'
def _generate_kin_2_envelope(): acc1 = gen_account_id() acc2 = gen_account_id() operations = [gen_kin_2_payment_op(acc2)] envelope_xdr = gen_tx_envelope_xdr(acc1, 1, operations, gen_text_memo(b'somememo')) return envelope_from_xdr(KIN_2_TEST_NETWORK, base64.b64encode(envelope_xdr))
def test_get_transaction(self, grpc_channel, executor, app_index_client): tx_hash = b'somehash' future = executor.submit(app_index_client.get_transaction, tx_hash) _, request, rpc = grpc_channel.take_unary_unary( tx_pb.DESCRIPTOR.services_by_name['Transaction'].methods_by_name['GetTransaction'] ) # Create full response op_result = gen_payment_op_result(xdr_const.PAYMENT_SUCCESS) result_xdr = gen_result_xdr(xdr_const.txSUCCESS, [op_result, op_result]) il = model_pb2.InvoiceList(invoices=[ model_pb2.Invoice( items=[ model_pb2.Invoice.LineItem(title='t1', amount=15), ] ), ]) fk = InvoiceList.from_proto(il).get_sha_224_hash() memo = AgoraMemo.new(1, TransactionType.EARN, 1, fk) hash_memo = gen_hash_memo(memo.val) acc1 = gen_account_id() acc2 = gen_account_id() operations = [gen_payment_op(acc2, amount=15)] envelope_xdr = gen_tx_envelope_xdr(acc1, 1, operations, hash_memo) history_item = tx_pb.HistoryItem( hash=model_pb2.TransactionHash(value=tx_hash), result_xdr=result_xdr, envelope_xdr=envelope_xdr, cursor=tx_pb.Cursor(value=b'cursor1'), invoice_list=il, ) resp = tx_pb.GetTransactionResponse( state=tx_pb.GetTransactionResponse.State.SUCCESS, ledger=10, item=history_item, ) rpc.terminate(resp, (), grpc.StatusCode.OK, '') tx_data = future.result() assert tx_data.tx_hash == tx_hash assert len(tx_data.payments) == 1 assert not tx_data.error payment1 = tx_data.payments[0] assert payment1.sender.raw == acc1.ed25519 assert payment1.destination.raw == acc2.ed25519 assert payment1.tx_type == memo.tx_type() assert payment1.quarks == 15 assert (payment1.invoice.to_proto().SerializeToString() == il.invoices[0].SerializeToString()) assert not payment1.memo assert request.transaction_hash.value == tx_hash
def test_from_proto_agora_memo(self): op_result = gen_payment_op_result(xdr_const.PAYMENT_SUCCESS) result_xdr = gen_result_xdr(xdr_const.txSUCCESS, [op_result, op_result]) il = model_pb2.InvoiceList(invoices=[ model_pb2.Invoice(items=[ model_pb2.Invoice.LineItem(title='t1', amount=10), ]), model_pb2.Invoice(items=[ model_pb2.Invoice.LineItem(title='t1', amount=15), ]), ]) fk = InvoiceList.from_proto(il).get_sha_224_hash() memo = AgoraMemo.new(1, TransactionType.P2P, 0, fk) hash_memo = gen_hash_memo(memo.val) acc1 = gen_account_id() acc2 = gen_account_id() acc3 = gen_account_id() operations = [ gen_payment_op(acc2, src=acc1, amount=10), gen_payment_op(acc1, src=acc2, amount=15), ] envelope_xdr = gen_tx_envelope_xdr(acc3, 1, operations, hash_memo) history_item = tx_pb.HistoryItem( hash=model_pb2.TransactionHash(value=b'somehash'), result_xdr=result_xdr, envelope_xdr=envelope_xdr, cursor=tx_pb.Cursor(value=b'cursor1'), invoice_list=il, ) data = TransactionData.from_proto(history_item) assert data.tx_hash == b'somehash' assert len(data.payments) == 2 payment1 = data.payments[0] assert payment1.sender.raw == acc1.ed25519 assert payment1.destination.raw == acc2.ed25519 assert payment1.tx_type == memo.tx_type() assert payment1.quarks == 10 assert (payment1.invoice.to_proto().SerializeToString() == il.invoices[0].SerializeToString()) assert not payment1.memo payment2 = data.payments[1] assert payment2.sender.raw == acc2.ed25519 assert payment2.destination.raw == acc1.ed25519 assert payment2.tx_type == TransactionType.P2P assert payment2.quarks == 15 assert (payment2.invoice.to_proto().SerializeToString() == il.invoices[1].SerializeToString()) assert not payment2.memo
def test_payments_from_envelope_with_invoice_list(self): il = model_pb2.InvoiceList(invoices=[ model_pb2.Invoice( items=[ model_pb2.Invoice.LineItem(title='t1', amount=10), ] ), model_pb2.Invoice( items=[ model_pb2.Invoice.LineItem(title='t1', amount=15), ] ), ]) fk = InvoiceList.from_proto(il).get_sha_224_hash() memo = AgoraMemo.new(1, TransactionType.P2P, 0, fk) hash_memo = gen_hash_memo(memo.val) acc1 = gen_account_id() acc2 = gen_account_id() acc3 = gen_account_id() operations = [gen_payment_op(acc2, amount=20), gen_payment_op(acc3, src=acc2, amount=40)] envelope_xdr = gen_tx_envelope_xdr(acc1, 1, operations, hash_memo) env = te.TransactionEnvelope.from_xdr(base64.b64encode(envelope_xdr)) payments = ReadOnlyPayment.payments_from_envelope(env, il) assert len(payments) == 2 assert payments[0].sender.raw == acc1.ed25519 assert payments[0].destination.raw == acc2.ed25519 assert payments[0].tx_type == TransactionType.P2P assert payments[0].quarks == 20 assert payments[0].invoice == Invoice.from_proto(il.invoices[0]) assert not payments[0].memo assert payments[1].sender.raw == acc2.ed25519 assert payments[1].destination.raw == acc3.ed25519 assert payments[1].tx_type == TransactionType.P2P assert payments[1].quarks == 40 assert payments[1].invoice == Invoice.from_proto(il.invoices[1]) assert not payments[1].memo
def test_from_proto_stellar_text_memo(self): op_result = gen_payment_op_result(xdr_const.PAYMENT_UNDERFUNDED) result_xdr = gen_result_xdr(xdr_const.txFAILED, [op_result]) tx_src = gen_account_id() dest = gen_account_id() operations = [gen_payment_op(dest, amount=20)] envelope_xdr = gen_tx_envelope_xdr(tx_src, 1, operations, gen_text_memo(b'somememo')) history_item = tx_pb.HistoryItem( transaction_id=model_pb.TransactionId(value=b'somehash'), cursor=tx_pb.Cursor(value=b'cursor1'), stellar_transaction=model_pb.StellarTransaction( result_xdr=result_xdr, envelope_xdr=envelope_xdr, ), payments=[ tx_pb.HistoryItem.Payment( source=model_pb.SolanaAccountId(value=tx_src.ed25519), destination=model_pb.SolanaAccountId(value=dest.ed25519), amount=20, ), ], ) data = TransactionData.from_proto( history_item, tx_pb.GetTransactionResponse.State.SUCCESS) assert data.tx_id == b'somehash' assert data.transaction_state == TransactionState.SUCCESS assert len(data.payments) == 1 payment = data.payments[0] assert payment.sender.raw == tx_src.ed25519 assert payment.destination.raw == dest.ed25519 assert payment.tx_type == TransactionType.UNKNOWN assert payment.quarks == 20 assert not payment.invoice assert payment.memo == 'somememo'
def test_handle_sign_transaction(self): secret = 'secret' handler = WebhookHandler(secret=secret) acc1 = gen_account_id() acc2 = gen_account_id() operations = [gen_payment_op(acc2)] envelope_xdr = gen_tx_envelope_xdr(acc1, 1, operations, gen_text_memo(b'somememo')) data = { 'kin_version': 3, 'envelope_xdr': base64.b64encode(envelope_xdr).decode() } req_body = json.dumps(data) sig = base64.b64encode(hmac.new(secret.encode(), req_body.encode(), hashlib.sha256).digest()) text_sig = base64.b64encode(hmac.new(secret.encode(), b'someotherdata', hashlib.sha256).digest()) # invalid signature status_code, resp_body = handler.handle_sign_transaction(self._sign_tx_success, text_sig, req_body) assert status_code == 401 assert resp_body == '' # invalid req body status_code, resp_body = handler.handle_sign_transaction(self._sign_tx_success, text_sig, 'someotherdata') assert status_code == 400 assert resp_body == 'invalid request body' # webhook request error status_code, resp_body = handler.handle_sign_transaction(self._sign_tx_raise_webhook_request_error, sig, req_body) assert status_code == 400 assert resp_body == 'some error' # other error status_code, resp_body = handler.handle_sign_transaction(self._sign_tx_raise_other_error, sig, req_body) assert status_code == 500 assert resp_body == 'bad stuff' # rejected status_code, resp_body = handler.handle_sign_transaction(self._sign_tx_return_rejected, sig, req_body) assert status_code == 403 assert json.loads(resp_body) == { 'invoice_errors': [ {'operation_index': 0, 'reason': InvoiceErrorReason.UNKNOWN.to_lowercase()} ] } # successful status_code, resp_body = handler.handle_sign_transaction(self._sign_tx_success, sig, req_body) assert status_code == 200 actual_env = te.TransactionEnvelope.from_xdr(json.loads(resp_body)['envelope_xdr']) _TEST_PRIVATE_KEY.verify(actual_env.hash_meta(), actual_env.signatures[-1].signature) # fake signature with no webhook secret should result in a successful response handler = WebhookHandler() status_code, resp_body = handler.handle_sign_transaction(self._sign_tx_success, "fakesig", req_body) assert status_code == 200 actual_env = te.TransactionEnvelope.from_xdr(json.loads(resp_body)['envelope_xdr']) _TEST_PRIVATE_KEY.verify(actual_env.hash_meta(), actual_env.signatures[-1].signature)