diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinTestNetConfig.java b/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinTestNetConfig.java
index 1fb3c3d48..10ee8366f 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinTestNetConfig.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/payments/MobileCoinTestNetConfig.java
@@ -56,12 +56,12 @@ final class MobileCoinTestNetConfig extends MobileCoinConfig {
ClientConfig config = new ClientConfig();
String[] hardeningAdvisories = { "INTEL-SA-00334", "INTEL-SA-00615" };
VerifierFactory verifierFactory = new VerifierFactory(hardeningAdvisories,
- // ~July 15, 2022
+ // ~August 15, 2022
new ServiceConfig(
- "4f134dcfd9c0885956f2f9af0f05c2050d8bdee2dc63b468a640670d7adeb7f8",
- "8f2f3bf81f24bf493fa6d76e29e0f081815022592b1e854f95bda750aece7452",
- "685481b33f2846585f33506ab65649c98a4a6d1244989651fd0fcde904ebd82f",
- "719ca43abbe02f507bb91ea11ff8bc900aa86363a7d7e77b8130426fc53d8684"
+ "01746f4dd25f8623d603534425ed45833687eca2b3ba25bdd87180b9471dac28",
+ "3e9bf61f3191add7b054f0e591b62f832854606f6594fd63faef1e2aedec4021",
+ "92fb35d0f603ceb5eaf2988b24a41d4a4a83f8fb9cd72e67c3bc37960d864ad6",
+ "3d6e528ee0574ae3299915ea608b71ddd17cbe855d4f5e1c46df9b0d22b04cdb"
));
config.logAdapter = new MobileCoinLogAdapter();
diff --git a/app/src/main/java/org/thoughtcrime/securesms/payments/Wallet.java b/app/src/main/java/org/thoughtcrime/securesms/payments/Wallet.java
index 9c966f057..bd956198e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/payments/Wallet.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/payments/Wallet.java
@@ -54,13 +54,17 @@ import java.util.concurrent.TimeoutException;
public final class Wallet {
- private static final String TAG = Log.tag(Wallet.class);
+ private static final String TAG = Log.tag(Wallet.class);
+ private static final Object LEDGER_LOCK = new Object();
private final MobileCoinConfig mobileCoinConfig;
private final MobileCoinClient mobileCoinClient;
private final AccountKey account;
private final MobileCoinPublicAddress publicAddress;
+ private AccountSnapshot cachedAccountSnapshot;
+ private Amount cachedMinimumTxFee;
+
public Wallet(@NonNull MobileCoinConfig mobileCoinConfig, @NonNull Entropy paymentsEntropy) {
this.mobileCoinConfig = mobileCoinConfig;
try {
@@ -122,6 +126,12 @@ public final class Wallet {
return getCachedLedger();
}
+ /**
+ * Retrieve a user owned ledger
+ * @param minimumBlockIndex require the returned ledger to include all TxOuts to at least minimumBlockIndex
+ * @return a wrapped MobileCoin ledger that contains only TxOuts owned by the AccountKey
+ * or null if the requested minimumBlockIndex cannot be retrieved
+ */
@WorkerThread
public @Nullable MobileCoinLedgerWrapper tryGetFullLedger(@Nullable Long minimumBlockIndex) throws IOException, FogSyncException {
try {
@@ -130,8 +140,16 @@ public final class Wallet {
long highestBlockTimeStamp = 0;
UnsignedLong highestBlockIndex = UnsignedLong.ZERO;
final long asOfTimestamp = System.currentTimeMillis();
- AccountSnapshot accountSnapshot = mobileCoinClient.getAccountSnapshot();
- final Amount minimumTxFee = mobileCoinClient.getOrFetchMinimumTxFee(TokenId.MOB);
+ Amount minimumTxFee;
+ AccountSnapshot accountSnapshot;
+
+ synchronized (LEDGER_LOCK) {
+ minimumTxFee = mobileCoinClient.getOrFetchMinimumTxFee(TokenId.MOB);
+ accountSnapshot = mobileCoinClient.getAccountSnapshot();
+
+ cachedMinimumTxFee = minimumTxFee;
+ cachedAccountSnapshot = accountSnapshot;
+ }
if (minimumBlockIndex != null) {
long snapshotBlockIndex = accountSnapshot.getBlockIndex().longValue();
@@ -212,8 +230,14 @@ public final class Wallet {
@WorkerThread
public @NonNull Money.MobileCoin getFee(@NonNull Money.MobileCoin amount) throws IOException {
try {
- BigInteger picoMob = amount.requireMobileCoin().toPicoMobBigInteger();
- return Money.picoMobileCoin(mobileCoinClient.estimateTotalFee(Amount.ofMOB(picoMob)).getValue());
+ BigInteger picoMob = amount.requireMobileCoin().toPicoMobBigInteger();
+ AccountSnapshot accountSnapshot = getCachedAccountSnapshot();
+ Amount minimumFee = getCachedMinimumTxFee();
+ if (accountSnapshot != null && minimumFee != null) {
+ return Money.picoMobileCoin(accountSnapshot.estimateTotalFee(Amount.ofMOB(picoMob), minimumFee).getValue());
+ } else {
+ return Money.picoMobileCoin(mobileCoinClient.estimateTotalFee(Amount.ofMOB(picoMob)).getValue());
+ }
} catch (InvalidFogResponse | AttestationException | InsufficientFundsException e) {
Log.w(TAG, "Failed to get fee", e);
return Money.MobileCoin.ZERO;
@@ -238,9 +262,7 @@ public final class Wallet {
try {
PaymentTransactionId.MobileCoin mobcoinTransaction = (PaymentTransactionId.MobileCoin) transactionId;
Transaction transaction = Transaction.fromBytes(mobcoinTransaction.getTransaction());
- Transaction.Status status = mobileCoinClient.getAccountSnapshot()
- .getTransactionStatus(transaction);
-
+ Transaction.Status status = mobileCoinClient.getTransactionStatusQuick(transaction);
switch (status) {
case UNKNOWN:
Log.w(TAG, "Unknown sent Transaction Status");
@@ -252,10 +274,10 @@ public final class Wallet {
default:
throw new IllegalStateException("Unknown Transaction Status: " + status);
}
- } catch (SerializationException | InvalidFogResponse e) {
+ } catch (SerializationException e) {
Log.w(TAG, e);
return TransactionStatusResult.failed();
- } catch (NetworkException | AttestationException e) {
+ } catch (NetworkException e) {
Log.w(TAG, e);
throw new IOException(e);
}
@@ -324,10 +346,18 @@ public final class Wallet {
}
try {
- pendingTransaction = mobileCoinClient.prepareTransaction(to.getAddress(),
- Amount.ofMOB(picoMob),
- Amount.ofMOB(feeMobileCoin.toPicoMobBigInteger()),
- TxOutMemoBuilder.createSenderAndDestinationRTHMemoBuilder(account));
+ AccountSnapshot accountSnapshot = getCachedAccountSnapshot();
+ if (accountSnapshot != null) {
+ pendingTransaction = accountSnapshot.prepareTransaction(to.getAddress(),
+ Amount.ofMOB(picoMob),
+ Amount.ofMOB(feeMobileCoin.toPicoMobBigInteger()),
+ TxOutMemoBuilder.createSenderAndDestinationRTHMemoBuilder(account));
+ } else {
+ pendingTransaction = mobileCoinClient.prepareTransaction(to.getAddress(),
+ Amount.ofMOB(picoMob),
+ Amount.ofMOB(feeMobileCoin.toPicoMobBigInteger()),
+ TxOutMemoBuilder.createSenderAndDestinationRTHMemoBuilder(account));
+ }
} catch (InsufficientFundsException e) {
Log.w(TAG, "Insufficient funds", e);
results.add(TransactionSubmissionResult.failure(TransactionSubmissionResult.ErrorCode.INSUFFICIENT_FUNDS, false));
@@ -408,6 +438,30 @@ public final class Wallet {
getFullLedger();
}
+ /**
+ * @return cached account snapshot or null if it's not available
+ * @apiNote This method is synchronized with {@link #tryGetFullLedger}
+ * to wait for an updated value if ledger update is in progress.
+ */
+ @WorkerThread
+ private @Nullable AccountSnapshot getCachedAccountSnapshot() {
+ synchronized (LEDGER_LOCK) {
+ return cachedAccountSnapshot;
+ }
+ }
+
+ /**
+ * @return cached minimum transaction fee or null if it's not available
+ * @apiNote This method is synchronized with {@link #tryGetFullLedger}
+ * to wait for an updated value if ledger update is in progress.
+ */
+ @WorkerThread
+ private @Nullable Amount getCachedMinimumTxFee() {
+ synchronized (LEDGER_LOCK) {
+ return cachedMinimumTxFee;
+ }
+ }
+
public enum TransactionStatus {
COMPLETE,
IN_PROGRESS,
diff --git a/dependencies.gradle b/dependencies.gradle
index e962ac4c7..3ecb00619 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -93,7 +93,7 @@ dependencyResolutionManagement {
alias('rxjava3-rxkotlin').to('io.reactivex.rxjava3:rxkotlin:3.0.1')
alias('rxdogtag').to('com.uber.rxdogtag2:rxdogtag:2.0.1')
alias('conscrypt-android').to('org.conscrypt:conscrypt-android:2.0.0')
- alias('mobilecoin').to('com.mobilecoin:android-sdk:1.2.2.2')
+ alias('mobilecoin').to('com.mobilecoin:android-sdk:1.2.2.4')
alias('leolin-shortcutbadger').to('me.leolin:ShortcutBadger:1.1.22')
alias('emilsjolander-stickylistheaders').to('se.emilsjolander:stickylistheaders:2.7.0')
alias('jpardogo-materialtabstrip').to('com.jpardogo.materialtabstrip:library:1.0.9')
@@ -153,4 +153,4 @@ dependencyResolutionManagement {
alias('lint-tests').to('com.android.tools.lint', 'lint-tests').versionRef('lint')
}
}
-}
\ No newline at end of file
+}
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 799f28e96..4a9d20bc1 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -1983,9 +1983,9 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
-
-
-
+
+
+