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);
}
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;
}
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());
}
}
}
}
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());
}
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());
}
Aggregations