コード例 #1
0
    def test_errors_from_solana_tx(self, instruction_index, exp_op_index, exp_payment_index):
        keys = [pk.public_key for pk in generate_keys(4)]
        tx = solana.Transaction.new(
            keys[0],
            [
                memo.memo_instruction('data'),
                token.transfer(keys[1], keys[2], keys[1], 100),
                token.set_authority(keys[1], keys[1], token.AuthorityType.CLOSE_ACCOUNT, keys[3])
            ]
        )
        tx_id = b'tx_sig'

        errors = TransactionErrors.from_solana_tx(tx, model_pbv4.TransactionError(
            reason=model_pbv4.TransactionError.Reason.INSUFFICIENT_FUNDS,
            instruction_index=instruction_index,
        ), tx_id)
        assert isinstance(errors.tx_error, InsufficientBalanceError)
        assert len(errors.op_errors) == 3
        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) == 1
            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
コード例 #2
0
    def from_proto(
        cls, item: tx_pb_v4.HistoryItem, state: tx_pb_v4.GetTransactionResponse.State
    ) -> 'TransactionData':
        payments = []
        if item.invoice_list and item.invoice_list.invoices:
            if len(item.payments) != len(item.invoice_list.invoices):
                raise ValueError('number of invoices does not match number of payments')
            il = InvoiceList.from_proto(item.invoice_list)
        else:
            il = None

        tx_type = TransactionType.UNKNOWN
        memo = None
        tx_errors = None
        if item.solana_transaction.value:
            solana_tx = solana.Transaction.unmarshal(item.solana_transaction.value)
            program_idx = solana_tx.message.instructions[0].program_index
            if solana_tx.message.accounts[program_idx] == solana.MEMO_PROGRAM_KEY:
                decompiled_memo = solana.decompile_memo(solana_tx.message, 0)
                memo_data = decompiled_memo.data.decode('utf-8')
                try:
                    agora_memo = AgoraMemo.from_b64_string(memo_data)
                    tx_type = agora_memo.tx_type()
                except ValueError:
                    memo = memo_data
            tx_errors = TransactionErrors.from_solana_tx(solana_tx, item.transaction_error, item.transaction_id.value)
        elif item.stellar_transaction.envelope_xdr:
            env = te.TransactionEnvelope.from_xdr(base64.b64encode(item.stellar_transaction.envelope_xdr))
            tx = env.tx
            if isinstance(tx.memo, stellar_memo.HashMemo):
                try:
                    agora_memo = AgoraMemo.from_base_memo(tx.memo)
                    tx_type = agora_memo.tx_type()
                except ValueError:
                    pass
            elif isinstance(tx.memo, stellar_memo.TextMemo):
                memo = tx.memo.text.decode()

            tx_errors = TransactionErrors.from_stellar_tx(env, item.transaction_error, item.transaction_id.value)

        for idx, p in enumerate(item.payments):
            inv = il.invoices[idx] if il and il.invoices else None
            payments.append(ReadOnlyPayment(PublicKey(p.source.value), PublicKey(p.destination.value),
                                            tx_type, p.amount, invoice=inv, memo=memo))

        return cls(
            item.transaction_id.value,
            TransactionState.from_proto_v4(state),
            payments,
            error=tx_errors,
        )
コード例 #3
0
        def _submit_request():
            nonlocal attempt

            attempt += 1
            req = tx_pb.SubmitTransactionRequest(
                transaction=model_pb.Transaction(value=tx_bytes, ),
                invoice_list=invoice_list.to_proto() if invoice_list else None,
                commitment=commitment.to_proto(),
                dedupe_id=dedupe_id,
            )
            resp = self._transaction_stub_v4.SubmitTransaction(
                req, metadata=self._metadata, timeout=_GRPC_TIMEOUT_SECONDS)

            if resp.result == tx_pb.SubmitTransactionResponse.Result.REJECTED:
                raise TransactionRejectedError()
            if resp.result == tx_pb.SubmitTransactionResponse.Result.PAYER_REQUIRED:
                raise PayerRequiredError()

            result = SubmitTransactionResult(tx_id=resp.signature.value)
            if resp.result == tx_pb.SubmitTransactionResponse.Result.ALREADY_SUBMITTED:
                # If this occurs on the first attempt, it's likely due to the submission of two identical transactions
                # in quick succession and we should raise the error to the caller. Otherwise, it's likely that the
                # transaction completed successfully on a previous attempt that failed due to a transient error.
                if attempt == 1:
                    raise AlreadySubmittedError(tx_id=resp.signature.value)
            elif resp.result == tx_pb.SubmitTransactionResponse.Result.FAILED:
                result.errors = TransactionErrors.from_solana_tx(
                    tx, resp.transaction_error, resp.signature.value)
            elif resp.result == tx_pb.SubmitTransactionResponse.Result.INVOICE_ERROR:
                result.invoice_errors = resp.invoice_errors
            elif resp.result != tx_pb.SubmitTransactionResponse.Result.OK:
                raise TransactionError(
                    f'unexpected result from agora: {resp.result}',
                    tx_id=resp.signature.value)

            return result