diff --git a/README.md b/README.md index c076744f..391493eb 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ walletFull.close(true); #### For Gradle, add to build.gradle: -`compile 'io.github.woodser:monero-java:0.8.55'` +`compile 'io.github.woodser:monero-java:0.8.56'` #### For Maven, add to pom.xml: @@ -105,7 +105,7 @@ walletFull.close(true); io.github.woodser monero-java - 0.8.55 + 0.8.56 ``` diff --git a/external/monero-cpp b/external/monero-cpp index 8db4afab..6927f7bf 160000 --- a/external/monero-cpp +++ b/external/monero-cpp @@ -1 +1 @@ -Subproject commit 8db4afab28f394f3dc78de6b4c2d3473484ce1b9 +Subproject commit 6927f7bf52dabad2179dfe2a0a0e1a95e12290c1 diff --git a/pom.xml b/pom.xml index 51a31d74..387b765a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 io.github.woodser monero-java - 0.8.55 + 0.8.56 Monero Java Library A Java library for using Monero https://github.com/woodser/monero-java diff --git a/src/main/cpp/monero_jni_bridge.cpp b/src/main/cpp/monero_jni_bridge.cpp index d7d22623..a2bed5a1 100644 --- a/src/main/cpp/monero_jni_bridge.cpp +++ b/src/main/cpp/monero_jni_bridge.cpp @@ -1428,10 +1428,10 @@ JNIEXPORT jstring JNICALL Java_monero_wallet_MoneroWalletFull_describeTxSetJni(J try { // deserialize tx set to describe - monero_tx_set tx_set = monero_tx_set::deserialize(tx_set_json); + shared_ptr tx_set = monero_tx_set::deserialize(tx_set_json); // describe tx set - monero_tx_set described_tx_set = wallet->describe_tx_set(tx_set); + monero_tx_set described_tx_set = wallet->describe_tx_set(*tx_set); // serialize, free, and return std::string monero_tx_set_json = described_tx_set.serialize(); diff --git a/src/main/java/monero/common/MoneroUtils.java b/src/main/java/monero/common/MoneroUtils.java index ad397f0c..e8593ac5 100644 --- a/src/main/java/monero/common/MoneroUtils.java +++ b/src/main/java/monero/common/MoneroUtils.java @@ -42,7 +42,7 @@ public class MoneroUtils { * @return the version of this monero-java library */ public static String getVersion() { - return "0.8.55"; + return "0.8.56"; } /** diff --git a/src/main/java/monero/common/TaskLooper.java b/src/main/java/monero/common/TaskLooper.java index 0afd82f8..a2d24c3a 100644 --- a/src/main/java/monero/common/TaskLooper.java +++ b/src/main/java/monero/common/TaskLooper.java @@ -54,15 +54,23 @@ public synchronized TaskLooper start(long periodInMs, boolean targetFixedPeriod) if (isStarted) return this; isStarted = true; - // start looping + // reuse a live loop, which observes isStarted under lock and continues if (isLooping) return this; isLooping = true; TaskLooper that = this; Thread loop = new Thread(new Runnable() { @Override public void run() { - while (isStarted && !Thread.currentThread().isInterrupted()) { - + while (true) { + + // decide to exit and clear isLooping atomically so a restart cannot reuse a dead loop + synchronized (that) { + if (!isStarted || Thread.currentThread().isInterrupted()) { + isLooping = false; + return; + } + } + // run the task long startTime = System.currentTimeMillis(); task.run(); @@ -71,12 +79,12 @@ public void run() { if (isStarted) { try { TimeUnit.MILLISECONDS.sleep(that.periodInMs - (targetFixedPeriod ? System.currentTimeMillis() - startTime : 0)); } // target fixed period by accounting for run time catch (Exception e) { - isLooping = false; + synchronized (that) { isLooping = false; } if (isStarted) throw new RuntimeException(e); + return; } } } - isLooping = false; } }); loop.start(); diff --git a/src/main/java/monero/wallet/MoneroWalletRpc.java b/src/main/java/monero/wallet/MoneroWalletRpc.java index 26e87934..cb6b2604 100644 --- a/src/main/java/monero/wallet/MoneroWalletRpc.java +++ b/src/main/java/monero/wallet/MoneroWalletRpc.java @@ -2421,8 +2421,14 @@ public void poll() { // announce new unlocked outputs for (MoneroTxWallet unlockedTx : unlockedTxs) { + boolean missedConfirm = Boolean.TRUE.equals(unlockedTx.isConfirmed()) && !prevConfirmedNotifications.contains(unlockedTx.getHash()); prevUnconfirmedNotifications.remove(unlockedTx.getHash()); // stop tracking tx notifications prevConfirmedNotifications.remove(unlockedTx.getHash()); + if (missedConfirm) { // announce missed confirm transition if tx unlocked between polls + MoneroTxWallet confirmedTx = unlockedTx.copy().setIsLocked(true); + confirmedTx.setBlock(unlockedTx.getBlock().copy().setTxs(confirmedTx)); + notifyOutputs(confirmedTx); + } notifyOutputs(unlockedTx); } diff --git a/src/test/java/TestMoneroWalletFull.java b/src/test/java/TestMoneroWalletFull.java index 4275b2ba..8c77fc2a 100644 --- a/src/test/java/TestMoneroWalletFull.java +++ b/src/test/java/TestMoneroWalletFull.java @@ -251,8 +251,9 @@ public void testCreateWalletRandomFull() { // cannot get daemon chain height try { wallet.getDaemonHeight(); + fail("Should have thrown exception"); } catch (MoneroError e) { - assertEquals("Wallet is not connected to daemon", e.getMessage()); + assertEquals("daemon error", e.getMessage()); // wallet2 masks errors from untrusted daemons } // set daemon connection and check chain height @@ -307,7 +308,7 @@ public void testCreateWalletFromSeedFull() { assertFalse(wallet.isSynced()); assertEquals(1, wallet.getHeight()); assertEquals(0, wallet.getRestoreHeight()); - try { wallet.startSyncing(); } catch (MoneroError e) { assertEquals("Wallet is not connected to daemon", e.getMessage()); } + wallet.startSyncing(); // succeeds while offline, syncing when a daemon becomes reachable wallet.close(); // create wallet without restore height @@ -771,9 +772,7 @@ public void testStartStopSyncing() { assertNotNull(wallet.getSeed()); assertEquals(1, wallet.getHeight()); assertEquals(BigInteger.valueOf(0), wallet.getBalance()); - wallet.startSyncing(); - } catch (MoneroError e) { - assertEquals("Wallet is not connected to daemon", e.getMessage()); + wallet.startSyncing(); // succeeds while offline, syncing when a daemon becomes reachable } finally { wallet.close(); }