Search in sources :

Example 26 with Payment

use of org.thoughtcrime.securesms.payments.Payment in project Signal-Android by signalapp.

the class LedgerReconcile method reconcile.

@WorkerThread
@NonNull
private static List<Payment> reconcile(@NonNull Collection<? extends Payment> allLocalPaymentTransactions, @NonNull List<MobileCoinLedgerWrapper.OwnedTxo> allTxOuts) {
    List<? extends Payment> nonFailedLocalPayments = Stream.of(allLocalPaymentTransactions).filter(i -> i.getState() != State.FAILED).toList();
    Set<ByteString> allKnownPublicKeys = new HashSet<>(nonFailedLocalPayments.size());
    Set<ByteString> allKnownKeyImages = new HashSet<>(nonFailedLocalPayments.size());
    for (Payment paymentTransaction : nonFailedLocalPayments) {
        PaymentMetaData.MobileCoinTxoIdentification txoIdentification = paymentTransaction.getPaymentMetaData().getMobileCoinTxoIdentification();
        allKnownPublicKeys.addAll(txoIdentification.getPublicKeyList());
        allKnownKeyImages.addAll(txoIdentification.getKeyImagesList());
    }
    Set<MobileCoinLedgerWrapper.OwnedTxo> knownTxosByKeyImage = Stream.of(allTxOuts).filter(t -> allKnownKeyImages.contains(t.getKeyImage())).collect(Collectors.toSet());
    Set<MobileCoinLedgerWrapper.OwnedTxo> knownTxosByPublicKeys = Stream.of(allTxOuts).filter(t -> allKnownPublicKeys.contains(t.getPublicKey())).collect(Collectors.toSet());
    // any TXO that we can't pair up the pub key for, we don't have detail for how it got into the account
    Set<MobileCoinLedgerWrapper.OwnedTxo> unknownTxOutsReceived = new HashSet<>(allTxOuts);
    unknownTxOutsReceived.removeAll(knownTxosByPublicKeys);
    // any TXO that we can't pair up the keyimage for, we don't have detail for how it got spent
    Set<MobileCoinLedgerWrapper.OwnedTxo> unknownTxOutsSpent = Stream.of(allTxOuts).filter(MobileCoinLedgerWrapper.OwnedTxo::isSpent).collect(Collectors.toSet());
    unknownTxOutsSpent.removeAll(knownTxosByKeyImage);
    if (unknownTxOutsReceived.isEmpty() && unknownTxOutsSpent.isEmpty()) {
        return Stream.of(allLocalPaymentTransactions).map(t -> (Payment) t).toList();
    }
    List<DetailedTransaction> detailedTransactions = reconstructAllTransactions(unknownTxOutsReceived, unknownTxOutsSpent);
    List<Payment> reconstructedPayments = new ArrayList<>(detailedTransactions.size());
    List<Payment> blockDecoratedLocalPayments = decoratePaymentsWithBlockIndexes(allLocalPaymentTransactions, allTxOuts);
    for (DetailedTransaction detailedTransaction : detailedTransactions) {
        reconstructedPayments.add(new ReconstructedPayment(detailedTransaction.blockDetail.getBlockIndex(), detailedTransaction.blockDetail.getBlockTimestampOrZero(), detailedTransaction.transaction.getDirection(), detailedTransaction.transaction.getValue()));
    }
    Collections.sort(reconstructedPayments, Payment.DESCENDING_BLOCK_INDEX);
    return ZipList.zipList(blockDecoratedLocalPayments, reconstructedPayments, Payment.DESCENDING_BLOCK_INDEX_UNKNOWN_FIRST);
}
Also used : PaymentMetaData(org.thoughtcrime.securesms.payments.proto.PaymentMetaData) PaymentDecorator(org.thoughtcrime.securesms.payments.PaymentDecorator) MapUtil(org.signal.core.util.MapUtil) Stream(com.annimon.stream.Stream) NonNull(androidx.annotation.NonNull) MobileCoinLedgerWrapper(org.thoughtcrime.securesms.payments.MobileCoinLedgerWrapper) WorkerThread(androidx.annotation.WorkerThread) HashMap(java.util.HashMap) ComparatorCompat(com.annimon.stream.ComparatorCompat) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Locale(java.util.Locale) Map(java.util.Map) TransactionReconstruction(org.thoughtcrime.securesms.payments.history.TransactionReconstruction) Nullable(javax.annotation.Nullable) State(org.thoughtcrime.securesms.payments.State) Collectors(com.annimon.stream.Collectors) Collection(java.util.Collection) Set(java.util.Set) ByteString(com.google.protobuf.ByteString) Log(org.signal.core.util.logging.Log) List(java.util.List) ReconstructedPayment(org.thoughtcrime.securesms.payments.ReconstructedPayment) Payment(org.thoughtcrime.securesms.payments.Payment) Comparator(java.util.Comparator) Collections(java.util.Collections) Money(org.whispersystems.signalservice.api.payments.Money) PaymentMetaData(org.thoughtcrime.securesms.payments.proto.PaymentMetaData) ByteString(com.google.protobuf.ByteString) ArrayList(java.util.ArrayList) ReconstructedPayment(org.thoughtcrime.securesms.payments.ReconstructedPayment) MobileCoinLedgerWrapper(org.thoughtcrime.securesms.payments.MobileCoinLedgerWrapper) ReconstructedPayment(org.thoughtcrime.securesms.payments.ReconstructedPayment) Payment(org.thoughtcrime.securesms.payments.Payment) HashSet(java.util.HashSet) WorkerThread(androidx.annotation.WorkerThread) NonNull(androidx.annotation.NonNull)

Example 27 with Payment

use of org.thoughtcrime.securesms.payments.Payment in project Signal-Android by signalapp.

the class LedgerReconcile method decoratePaymentsWithBlockIndexes.

private static List<Payment> decoratePaymentsWithBlockIndexes(@NonNull Collection<? extends Payment> localPaymentTransactions, @NonNull List<MobileCoinLedgerWrapper.OwnedTxo> allTxOuts) {
    List<Payment> result = new ArrayList<>(localPaymentTransactions.size());
    Map<ByteString, MobileCoinLedgerWrapper.OwnedTxo> blockDetailMap = new HashMap<>(allTxOuts.size() * 2);
    for (MobileCoinLedgerWrapper.OwnedTxo txo : allTxOuts) {
        blockDetailMap.put(txo.getPublicKey(), txo);
        blockDetailMap.put(txo.getKeyImage(), txo);
    }
    for (Payment local : localPaymentTransactions) {
        result.add(findBlock(local, blockDetailMap));
    }
    return result;
}
Also used : ReconstructedPayment(org.thoughtcrime.securesms.payments.ReconstructedPayment) Payment(org.thoughtcrime.securesms.payments.Payment) HashMap(java.util.HashMap) ByteString(com.google.protobuf.ByteString) ArrayList(java.util.ArrayList) MobileCoinLedgerWrapper(org.thoughtcrime.securesms.payments.MobileCoinLedgerWrapper)

Example 28 with Payment

use of org.thoughtcrime.securesms.payments.Payment in project Signal-Android by signalapp.

the class PaymentsRepository method updateDatabaseWithNewBlockInformation.

private void updateDatabaseWithNewBlockInformation(@NonNull List<Payment> reconcileOutput) {
    List<LedgerReconcile.BlockOverridePayment> blockOverridePayments = Stream.of(reconcileOutput).select(LedgerReconcile.BlockOverridePayment.class).toList();
    if (blockOverridePayments.isEmpty()) {
        return;
    }
    Log.i(TAG, String.format(Locale.US, "%d payments have new block index or timestamp information", blockOverridePayments.size()));
    for (LedgerReconcile.BlockOverridePayment blockOverridePayment : blockOverridePayments) {
        Payment inner = blockOverridePayment.getInner();
        boolean override = false;
        if (inner.getBlockIndex() != blockOverridePayment.getBlockIndex()) {
            override = true;
        }
        if (inner.getBlockTimestamp() != blockOverridePayment.getBlockTimestamp()) {
            override = true;
        }
        if (!override) {
            Log.w(TAG, "  Unnecessary");
        } else {
            if (paymentDatabase.updateBlockDetails(inner.getUuid(), blockOverridePayment.getBlockIndex(), blockOverridePayment.getBlockTimestamp())) {
                Log.d(TAG, "  Updated block details for " + inner.getUuid());
            } else {
                Log.w(TAG, "  Failed to update block details for " + inner.getUuid());
            }
        }
    }
}
Also used : Payment(org.thoughtcrime.securesms.payments.Payment) LedgerReconcile(org.thoughtcrime.securesms.payments.reconciliation.LedgerReconcile)

Example 29 with Payment

use of org.thoughtcrime.securesms.payments.Payment in project Signal-Android by signalapp.

the class LedgerReconcileTest method unknown_payment_is_first_in_list.

@Test
public void unknown_payment_is_first_in_list() {
    List<Payment> localPayments = Collections.singletonList(payment("received", mob(2.5), keyImages(16), publicKeys(12)));
    MobileCoinLedger ledger = ledger(spentTxo(mob(2.5), keyImage(5), publicKey(2), block(1), block(2)), unspentTxo(mob(1.5), keyImage(7), publicKey(8), block(3)));
    List<Payment> payments = reconcile(localPayments, new MobileCoinLedgerWrapper(ledger));
    assertEquals(Arrays.asList(mob(2.5), mob(1.5), mob(-2.5), mob(2.5)), Stream.of(payments).map(Payment::getAmountWithDirection).toList());
    assertEquals("received", payments.get(0).getNote());
}
Also used : Payment(org.thoughtcrime.securesms.payments.Payment) MobileCoinLedger(org.thoughtcrime.securesms.payments.proto.MobileCoinLedger) MobileCoinLedgerWrapper(org.thoughtcrime.securesms.payments.MobileCoinLedgerWrapper) Test(org.junit.Test)

Example 30 with Payment

use of org.thoughtcrime.securesms.payments.Payment in project Signal-Android by signalapp.

the class LedgerReconcileTest method single_receipt_payment_that_can_be_found_on_ledger_reconstructed_spend_but_not_with_change_due_to_block.

@Test
public void single_receipt_payment_that_can_be_found_on_ledger_reconstructed_spend_but_not_with_change_due_to_block() {
    List<Payment> localPayments = Collections.singletonList(payment("received", mob(2.5), keyImages(6), publicKeys(2)));
    MobileCoinLedger ledger = ledger(spentTxo(mob(2.5), keyImage(5), publicKey(2), block(1), block(2)), unspentTxo(mob(1.5), keyImage(7), publicKey(8), block(3)));
    List<Payment> payments = reconcile(localPayments, new MobileCoinLedgerWrapper(ledger));
    assertEquals(Arrays.asList(mob(1.5), mob(-2.5), mob(2.5)), Stream.of(payments).map(Payment::getAmountWithDirection).toList());
    assertEquals("received", payments.get(2).getNote());
}
Also used : Payment(org.thoughtcrime.securesms.payments.Payment) MobileCoinLedger(org.thoughtcrime.securesms.payments.proto.MobileCoinLedger) MobileCoinLedgerWrapper(org.thoughtcrime.securesms.payments.MobileCoinLedgerWrapper) Test(org.junit.Test)

Aggregations

Payment (org.thoughtcrime.securesms.payments.Payment)34 MobileCoinLedgerWrapper (org.thoughtcrime.securesms.payments.MobileCoinLedgerWrapper)28 Test (org.junit.Test)24 MobileCoinLedger (org.thoughtcrime.securesms.payments.proto.MobileCoinLedger)22 ByteString (com.google.protobuf.ByteString)4 ArrayList (java.util.ArrayList)4 HashMap (java.util.HashMap)4 ReconstructedPayment (org.thoughtcrime.securesms.payments.ReconstructedPayment)4 PaymentMetaData (org.thoughtcrime.securesms.payments.proto.PaymentMetaData)4 SpannableString (android.text.SpannableString)2 View (android.view.View)2 TextView (android.widget.TextView)2 NonNull (androidx.annotation.NonNull)2 WorkerThread (androidx.annotation.WorkerThread)2 Toolbar (androidx.appcompat.widget.Toolbar)2 Group (androidx.constraintlayout.widget.Group)2 FragmentActivity (androidx.fragment.app.FragmentActivity)2 Collectors (com.annimon.stream.Collectors)2 ComparatorCompat (com.annimon.stream.ComparatorCompat)2 Stream (com.annimon.stream.Stream)2