Search in sources :

Example 1 with InvalidFogResponse

use of com.mobilecoin.lib.exceptions.InvalidFogResponse in project Signal-Android by WhisperSystems.

the class Wallet method sendPayment.

@WorkerThread
private void sendPayment(@NonNull MobileCoinPublicAddress to, @NonNull Money.MobileCoin amount, @NonNull Money.MobileCoin totalFee, boolean defragmentFirst, @NonNull List<TransactionSubmissionResult> results) {
    Money.MobileCoin defragmentFees = Money.MobileCoin.ZERO;
    if (defragmentFirst) {
        try {
            defragmentFees = defragment(amount, results);
        } catch (InsufficientFundsException e) {
            Log.w(TAG, "Insufficient funds", e);
            results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.INSUFFICIENT_FUNDS, true));
            return;
        } catch (TimeoutException | InvalidTransactionException | InvalidFogResponse | AttestationException | TransactionBuilderException | NetworkException | FogReportException e) {
            Log.w(TAG, "Defragment failed", e);
            results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.GENERIC_FAILURE, true));
            return;
        }
    }
    Money.MobileCoin feeMobileCoin = totalFee.subtract(defragmentFees).requireMobileCoin();
    BigInteger picoMob = amount.requireMobileCoin().toPicoMobBigInteger();
    PendingTransaction pendingTransaction = null;
    Log.i(TAG, String.format("Total fee advised: %s\nDefrag fees: %s\nTransaction fee: %s", totalFee, defragmentFees, feeMobileCoin));
    if (!feeMobileCoin.isPositive()) {
        Log.i(TAG, "No fee left after defrag");
        results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.GENERIC_FAILURE, false));
        return;
    }
    try {
        pendingTransaction = mobileCoinClient.prepareTransaction(to.getAddress(), picoMob, feeMobileCoin.toPicoMobBigInteger());
    } catch (InsufficientFundsException e) {
        Log.w(TAG, "Insufficient funds", e);
        results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.INSUFFICIENT_FUNDS, false));
    } catch (FeeRejectedException e) {
        Log.w(TAG, "Fee rejected " + totalFee, e);
        results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.GENERIC_FAILURE, false));
    } catch (InvalidFogResponse | FogReportException e) {
        Log.w(TAG, "Invalid fog response", e);
        results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.GENERIC_FAILURE, false));
    } catch (FragmentedAccountException e) {
        if (defragmentFirst) {
            Log.w(TAG, "Account is fragmented, but already tried to defragment", e);
            results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.GENERIC_FAILURE, false));
        } else {
            Log.i(TAG, "Account is fragmented, defragmenting and retrying");
            sendPayment(to, amount, totalFee, true, results);
        }
    } catch (AttestationException e) {
        Log.w(TAG, "Attestation problem", e);
        results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.GENERIC_FAILURE, false));
    } catch (NetworkException e) {
        Log.w(TAG, "Network problem", e);
        results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.GENERIC_FAILURE, false));
    } catch (TransactionBuilderException e) {
        Log.w(TAG, "Builder problem", e);
        results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.GENERIC_FAILURE, false));
    }
    if (pendingTransaction == null) {
        Log.w(TAG, "Failed to create pending transaction");
        return;
    }
    try {
        Log.i(TAG, "Submitting transaction");
        mobileCoinClient.submitTransaction(pendingTransaction.getTransaction());
        Log.i(TAG, "Transaction submitted");
        results.add(TransactionSubmissionResult.successfullySubmitted(new PaymentTransactionId.MobileCoin(pendingTransaction.getTransaction().toByteArray(), pendingTransaction.getReceipt().toByteArray(), feeMobileCoin)));
    } catch (NetworkException e) {
        Log.w(TAG, "Network problem", e);
        results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.NETWORK_FAILURE, false));
    } catch (InvalidTransactionException e) {
        Log.w(TAG, "Invalid transaction", e);
        results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.GENERIC_FAILURE, false));
    } catch (AttestationException e) {
        Log.w(TAG, "Attestation problem", e);
        results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.GENERIC_FAILURE, false));
    } catch (SerializationException e) {
        Log.w(TAG, "Serialization problem", e);
        results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.GENERIC_FAILURE, false));
    }
}
Also used : PendingTransaction(com.mobilecoin.lib.PendingTransaction) AttestationException(com.mobilecoin.lib.exceptions.AttestationException) FogReportException(com.mobilecoin.lib.exceptions.FogReportException) SerializationException(com.mobilecoin.lib.exceptions.SerializationException) FeeRejectedException(com.mobilecoin.lib.exceptions.FeeRejectedException) InvalidTransactionException(com.mobilecoin.lib.exceptions.InvalidTransactionException) InvalidFogResponse(com.mobilecoin.lib.exceptions.InvalidFogResponse) TransactionBuilderException(com.mobilecoin.lib.exceptions.TransactionBuilderException) Money(org.whispersystems.signalservice.api.payments.Money) FragmentedAccountException(com.mobilecoin.lib.exceptions.FragmentedAccountException) InsufficientFundsException(com.mobilecoin.lib.exceptions.InsufficientFundsException) BigInteger(java.math.BigInteger) NetworkException(com.mobilecoin.lib.exceptions.NetworkException) TimeoutException(java.util.concurrent.TimeoutException) WorkerThread(androidx.annotation.WorkerThread)

Example 2 with InvalidFogResponse

use of com.mobilecoin.lib.exceptions.InvalidFogResponse in project Signal-Android by WhisperSystems.

the class Wallet method tryGetFullLedger.

@WorkerThread
@Nullable
public MobileCoinLedgerWrapper tryGetFullLedger(@Nullable Long minimumBlockIndex) throws IOException {
    try {
        MobileCoinLedger.Builder builder = MobileCoinLedger.newBuilder();
        BigInteger totalUnspent = BigInteger.ZERO;
        long highestBlockTimeStamp = 0;
        UnsignedLong highestBlockIndex = UnsignedLong.ZERO;
        final long asOfTimestamp = System.currentTimeMillis();
        AccountSnapshot accountSnapshot = mobileCoinClient.getAccountSnapshot();
        final BigInteger minimumTxFee = mobileCoinClient.getOrFetchMinimumTxFee();
        if (minimumBlockIndex != null) {
            long snapshotBlockIndex = accountSnapshot.getBlockIndex().longValue();
            if (snapshotBlockIndex < minimumBlockIndex) {
                Log.d(TAG, "Waiting for block index");
                return null;
            }
        }
        for (OwnedTxOut txOut : accountSnapshot.getAccountActivity().getAllTxOuts()) {
            MobileCoinLedger.OwnedTXO.Builder txoBuilder = MobileCoinLedger.OwnedTXO.newBuilder().setAmount(Uint64Util.bigIntegerToUInt64(txOut.getValue())).setReceivedInBlock(getBlock(txOut.getReceivedBlockIndex(), txOut.getReceivedBlockTimestamp())).setKeyImage(ByteString.copyFrom(txOut.getKeyImage().getData())).setPublicKey(ByteString.copyFrom(txOut.getPublicKey().getKeyBytes()));
            if (txOut.getSpentBlockIndex() != null && (minimumBlockIndex == null || txOut.isSpent(UnsignedLong.valueOf(minimumBlockIndex)))) {
                txoBuilder.setSpentInBlock(getBlock(txOut.getSpentBlockIndex(), txOut.getSpentBlockTimestamp()));
                builder.addSpentTxos(txoBuilder);
            } else {
                totalUnspent = totalUnspent.add(txOut.getValue());
                builder.addUnspentTxos(txoBuilder);
            }
            if (txOut.getSpentBlockIndex() != null && txOut.getSpentBlockIndex().compareTo(highestBlockIndex) > 0) {
                highestBlockIndex = txOut.getSpentBlockIndex();
            }
            if (txOut.getReceivedBlockIndex().compareTo(highestBlockIndex) > 0) {
                highestBlockIndex = txOut.getReceivedBlockIndex();
            }
            if (txOut.getSpentBlockTimestamp() != null && txOut.getSpentBlockTimestamp().getTime() > highestBlockTimeStamp) {
                highestBlockTimeStamp = txOut.getSpentBlockTimestamp().getTime();
            }
            if (txOut.getReceivedBlockTimestamp() != null && txOut.getReceivedBlockTimestamp().getTime() > highestBlockTimeStamp) {
                highestBlockTimeStamp = txOut.getReceivedBlockTimestamp().getTime();
            }
        }
        builder.setBalance(Uint64Util.bigIntegerToUInt64(totalUnspent)).setTransferableBalance(Uint64Util.bigIntegerToUInt64(accountSnapshot.getTransferableAmount(minimumTxFee))).setAsOfTimeStamp(asOfTimestamp).setHighestBlock(MobileCoinLedger.Block.newBuilder().setBlockNumber(highestBlockIndex.longValue()).setTimestamp(highestBlockTimeStamp));
        return new MobileCoinLedgerWrapper(builder.build());
    } catch (InvalidFogResponse e) {
        Log.w(TAG, "Problem getting ledger", e);
        throw new IOException(e);
    } catch (NetworkException e) {
        Log.w(TAG, "Network problem getting ledger", e);
        if (e.statusCode == 401) {
            Log.d(TAG, "Reauthorizing client");
            reauthorizeClient();
        }
        throw new IOException(e);
    } catch (AttestationException e) {
        Log.w(TAG, "Attestation problem getting ledger", e);
        throw new IOException(e);
    } catch (Uint64RangeException e) {
        throw new AssertionError(e);
    }
}
Also used : AttestationException(com.mobilecoin.lib.exceptions.AttestationException) UnsignedLong(com.mobilecoin.lib.UnsignedLong) AccountSnapshot(com.mobilecoin.lib.AccountSnapshot) OwnedTxOut(com.mobilecoin.lib.OwnedTxOut) IOException(java.io.IOException) Uint64RangeException(org.whispersystems.signalservice.api.util.Uint64RangeException) MobileCoinLedger(org.thoughtcrime.securesms.payments.proto.MobileCoinLedger) InvalidFogResponse(com.mobilecoin.lib.exceptions.InvalidFogResponse) BigInteger(java.math.BigInteger) NetworkException(com.mobilecoin.lib.exceptions.NetworkException) WorkerThread(androidx.annotation.WorkerThread) Nullable(androidx.annotation.Nullable)

Example 3 with InvalidFogResponse

use of com.mobilecoin.lib.exceptions.InvalidFogResponse in project Signal-Android by WhisperSystems.

the class Wallet method getReceivedTransactionStatus.

@WorkerThread
@NonNull
public ReceivedTransactionStatus getReceivedTransactionStatus(@NonNull byte[] receiptBytes) throws IOException {
    try {
        Receipt receipt = Receipt.fromBytes(receiptBytes);
        Receipt.Status status = mobileCoinClient.getReceiptStatus(receipt);
        switch(status) {
            case UNKNOWN:
                Log.w(TAG, "Unknown received Transaction Status");
                return ReceivedTransactionStatus.inProgress();
            case FAILED:
                return ReceivedTransactionStatus.failed();
            case RECEIVED:
                BigInteger amount = receipt.getAmount(account);
                return ReceivedTransactionStatus.complete(Money.picoMobileCoin(amount), status.getBlockIndex().longValue());
            default:
                throw new IllegalStateException("Unknown Transaction Status: " + status);
        }
    } catch (SerializationException | InvalidFogResponse | InvalidReceiptException e) {
        Log.w(TAG, e);
        return ReceivedTransactionStatus.failed();
    } catch (NetworkException | AttestationException e) {
        throw new IOException(e);
    } catch (AmountDecoderException e) {
        Log.w(TAG, "Failed to decode amount", e);
        return ReceivedTransactionStatus.failed();
    }
}
Also used : AmountDecoderException(com.mobilecoin.lib.exceptions.AmountDecoderException) Receipt(com.mobilecoin.lib.Receipt) SerializationException(com.mobilecoin.lib.exceptions.SerializationException) AttestationException(com.mobilecoin.lib.exceptions.AttestationException) IOException(java.io.IOException) InvalidFogResponse(com.mobilecoin.lib.exceptions.InvalidFogResponse) BigInteger(java.math.BigInteger) InvalidReceiptException(com.mobilecoin.lib.exceptions.InvalidReceiptException) NetworkException(com.mobilecoin.lib.exceptions.NetworkException) WorkerThread(androidx.annotation.WorkerThread) NonNull(androidx.annotation.NonNull)

Example 4 with InvalidFogResponse

use of com.mobilecoin.lib.exceptions.InvalidFogResponse in project Signal-Android by WhisperSystems.

the class Wallet method getSentTransactionStatus.

@WorkerThread
@NonNull
public TransactionStatusResult getSentTransactionStatus(@NonNull PaymentTransactionId transactionId) throws IOException {
    try {
        PaymentTransactionId.MobileCoin mobcoinTransaction = (PaymentTransactionId.MobileCoin) transactionId;
        Transaction transaction = Transaction.fromBytes(mobcoinTransaction.getTransaction());
        Transaction.Status status = mobileCoinClient.getAccountSnapshot().getTransactionStatus(transaction);
        switch(status) {
            case UNKNOWN:
                Log.w(TAG, "Unknown sent Transaction Status");
                return TransactionStatusResult.inProgress();
            case FAILED:
                return TransactionStatusResult.failed();
            case ACCEPTED:
                return TransactionStatusResult.complete(status.getBlockIndex().longValue());
            default:
                throw new IllegalStateException("Unknown Transaction Status: " + status);
        }
    } catch (SerializationException | InvalidFogResponse e) {
        Log.w(TAG, e);
        return TransactionStatusResult.failed();
    } catch (NetworkException | AttestationException e) {
        Log.w(TAG, e);
        throw new IOException(e);
    }
}
Also used : SerializationException(com.mobilecoin.lib.exceptions.SerializationException) AttestationException(com.mobilecoin.lib.exceptions.AttestationException) IOException(java.io.IOException) InvalidFogResponse(com.mobilecoin.lib.exceptions.InvalidFogResponse) PendingTransaction(com.mobilecoin.lib.PendingTransaction) Transaction(com.mobilecoin.lib.Transaction) NetworkException(com.mobilecoin.lib.exceptions.NetworkException) WorkerThread(androidx.annotation.WorkerThread) NonNull(androidx.annotation.NonNull)

Aggregations

WorkerThread (androidx.annotation.WorkerThread)4 AttestationException (com.mobilecoin.lib.exceptions.AttestationException)4 InvalidFogResponse (com.mobilecoin.lib.exceptions.InvalidFogResponse)4 NetworkException (com.mobilecoin.lib.exceptions.NetworkException)4 SerializationException (com.mobilecoin.lib.exceptions.SerializationException)3 IOException (java.io.IOException)3 BigInteger (java.math.BigInteger)3 NonNull (androidx.annotation.NonNull)2 PendingTransaction (com.mobilecoin.lib.PendingTransaction)2 Nullable (androidx.annotation.Nullable)1 AccountSnapshot (com.mobilecoin.lib.AccountSnapshot)1 OwnedTxOut (com.mobilecoin.lib.OwnedTxOut)1 Receipt (com.mobilecoin.lib.Receipt)1 Transaction (com.mobilecoin.lib.Transaction)1 UnsignedLong (com.mobilecoin.lib.UnsignedLong)1 AmountDecoderException (com.mobilecoin.lib.exceptions.AmountDecoderException)1 FeeRejectedException (com.mobilecoin.lib.exceptions.FeeRejectedException)1 FogReportException (com.mobilecoin.lib.exceptions.FogReportException)1 FragmentedAccountException (com.mobilecoin.lib.exceptions.FragmentedAccountException)1 InsufficientFundsException (com.mobilecoin.lib.exceptions.InsufficientFundsException)1