start main wallet when daemon synced with improved UserThread
This commit is contained in:
parent
5466689857
commit
5d88936600
@ -45,7 +45,7 @@ public class UserThread {
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
private static Executor executor;
|
private static Executor executor;
|
||||||
private static final String USER_THREAD_NAME = "UserThread";
|
private static Thread USER_THREAD;
|
||||||
|
|
||||||
public static void setTimerClass(Class<? extends Timer> timerClass) {
|
public static void setTimerClass(Class<? extends Timer> timerClass) {
|
||||||
UserThread.timerClass = timerClass;
|
UserThread.timerClass = timerClass;
|
||||||
@ -59,8 +59,10 @@ public class UserThread {
|
|||||||
|
|
||||||
public static void execute(Runnable command) {
|
public static void execute(Runnable command) {
|
||||||
executor.execute(() -> {
|
executor.execute(() -> {
|
||||||
Thread.currentThread().setName(USER_THREAD_NAME);
|
synchronized (executor) {
|
||||||
command.run();
|
USER_THREAD = Thread.currentThread();
|
||||||
|
command.run();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,9 +81,9 @@ public class UserThread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: better way to determine if on UserThread, since this is not reliable
|
public static boolean isUserThread(Thread thread) {
|
||||||
private static boolean isUserThread(Thread thread) {
|
return thread == USER_THREAD;
|
||||||
return USER_THREAD_NAME.equals(thread.getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefer FxTimer if a delay is needed in a JavaFx class (gui module)
|
// Prefer FxTimer if a delay is needed in a JavaFx class (gui module)
|
||||||
@ -99,7 +101,7 @@ public class UserThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Timer runAfter(Runnable runnable, long delay, TimeUnit timeUnit) {
|
public static Timer runAfter(Runnable runnable, long delay, TimeUnit timeUnit) {
|
||||||
return getTimer().runLater(Duration.ofMillis(timeUnit.toMillis(delay)), runnable);
|
return getTimer().runLater(Duration.ofMillis(timeUnit.toMillis(delay)), () -> execute(runnable));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Timer runPeriodically(Runnable runnable, long intervalInSec) {
|
public static Timer runPeriodically(Runnable runnable, long intervalInSec) {
|
||||||
@ -107,7 +109,7 @@ public class UserThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Timer runPeriodically(Runnable runnable, long interval, TimeUnit timeUnit) {
|
public static Timer runPeriodically(Runnable runnable, long interval, TimeUnit timeUnit) {
|
||||||
return getTimer().runPeriodically(Duration.ofMillis(timeUnit.toMillis(interval)), runnable);
|
return getTimer().runPeriodically(Duration.ofMillis(timeUnit.toMillis(interval)), () -> execute(runnable));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Timer getTimer() {
|
private static Timer getTimer() {
|
||||||
|
@ -87,7 +87,6 @@ import javafx.collections.ListChangeListener;
|
|||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import monero.daemon.model.MoneroTx;
|
import monero.daemon.model.MoneroTx;
|
||||||
import monero.wallet.model.MoneroOutputQuery;
|
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bouncycastle.crypto.params.KeyParameter;
|
import org.bouncycastle.crypto.params.KeyParameter;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
@ -353,35 +352,6 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void thawUnreservedOutputs() {
|
|
||||||
if (xmrWalletService.getWallet() == null) return;
|
|
||||||
|
|
||||||
// collect reserved outputs
|
|
||||||
Set<String> reservedKeyImages = new HashSet<String>();
|
|
||||||
for (Trade trade : getObservableList()) {
|
|
||||||
if (trade.getSelf().getReserveTxKeyImages() == null) continue;
|
|
||||||
reservedKeyImages.addAll(trade.getSelf().getReserveTxKeyImages());
|
|
||||||
}
|
|
||||||
for (OpenOffer openOffer : openOfferManager.getObservableList()) {
|
|
||||||
if (openOffer.getOffer().getOfferPayload().getReserveTxKeyImages() == null) continue;
|
|
||||||
reservedKeyImages.addAll(openOffer.getOffer().getOfferPayload().getReserveTxKeyImages());
|
|
||||||
}
|
|
||||||
|
|
||||||
// thaw unreserved outputs
|
|
||||||
Set<String> unreservedFrozenKeyImages = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery()
|
|
||||||
.setIsFrozen(true)
|
|
||||||
.setIsSpent(false))
|
|
||||||
.stream()
|
|
||||||
.map(output -> output.getKeyImage().getHex())
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
unreservedFrozenKeyImages.removeAll(reservedKeyImages);
|
|
||||||
if (!unreservedFrozenKeyImages.isEmpty()) {
|
|
||||||
log.warn("Thawing outputs which are not reserved for offer or trade: " + unreservedFrozenKeyImages);
|
|
||||||
xmrWalletService.thawOutputs(unreservedFrozenKeyImages);
|
|
||||||
xmrWalletService.saveMainWallet();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TradeProtocol getTradeProtocol(Trade trade) {
|
public TradeProtocol getTradeProtocol(Trade trade) {
|
||||||
synchronized (tradeProtocolByTradeId) {
|
synchronized (tradeProtocolByTradeId) {
|
||||||
return tradeProtocolByTradeId.get(trade.getUid());
|
return tradeProtocolByTradeId.get(trade.getUid());
|
||||||
@ -464,9 +434,10 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// thaw unreserved outputs
|
// thaw unreserved outputs
|
||||||
thawUnreservedOutputs();
|
xmrWalletService.thawUnreservedOutputs();
|
||||||
|
|
||||||
// reset any available funded address entries
|
// reset any available funded address entries
|
||||||
|
if (isShutDownStarted) return;
|
||||||
xmrWalletService.getAddressEntriesForAvailableBalanceStream()
|
xmrWalletService.getAddressEntriesForAvailableBalanceStream()
|
||||||
.filter(addressEntry -> addressEntry.getOfferId() != null)
|
.filter(addressEntry -> addressEntry.getOfferId() != null)
|
||||||
.forEach(addressEntry -> {
|
.forEach(addressEntry -> {
|
||||||
@ -476,6 +447,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// notify that persisted trades initialized
|
// notify that persisted trades initialized
|
||||||
|
if (isShutDownStarted) return;
|
||||||
persistedTradesInitialized.set(true);
|
persistedTradesInitialized.set(true);
|
||||||
getObservableList().addListener((ListChangeListener<Trade>) change -> onTradesChanged());
|
getObservableList().addListener((ListChangeListener<Trade>) change -> onTradesChanged());
|
||||||
onTradesChanged();
|
onTradesChanged();
|
||||||
|
@ -12,6 +12,7 @@ import haveno.common.util.Utilities;
|
|||||||
import haveno.core.api.AccountServiceListener;
|
import haveno.core.api.AccountServiceListener;
|
||||||
import haveno.core.api.CoreAccountService;
|
import haveno.core.api.CoreAccountService;
|
||||||
import haveno.core.api.XmrConnectionService;
|
import haveno.core.api.XmrConnectionService;
|
||||||
|
import haveno.core.offer.OpenOffer;
|
||||||
import haveno.core.trade.BuyerTrade;
|
import haveno.core.trade.BuyerTrade;
|
||||||
import haveno.core.trade.HavenoUtils;
|
import haveno.core.trade.HavenoUtils;
|
||||||
import haveno.core.trade.MakerTrade;
|
import haveno.core.trade.MakerTrade;
|
||||||
@ -80,6 +81,7 @@ import java.util.stream.Stream;
|
|||||||
import javafx.beans.property.LongProperty;
|
import javafx.beans.property.LongProperty;
|
||||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||||
import javafx.beans.property.SimpleLongProperty;
|
import javafx.beans.property.SimpleLongProperty;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
|
||||||
@ -120,6 +122,7 @@ public class XmrWalletService {
|
|||||||
protected final CopyOnWriteArraySet<XmrBalanceListener> balanceListeners = new CopyOnWriteArraySet<>();
|
protected final CopyOnWriteArraySet<XmrBalanceListener> balanceListeners = new CopyOnWriteArraySet<>();
|
||||||
protected final CopyOnWriteArraySet<MoneroWalletListenerI> walletListeners = new CopyOnWriteArraySet<>();
|
protected final CopyOnWriteArraySet<MoneroWalletListenerI> walletListeners = new CopyOnWriteArraySet<>();
|
||||||
|
|
||||||
|
private ChangeListener<? super Number> walletInitListener;
|
||||||
private TradeManager tradeManager;
|
private TradeManager tradeManager;
|
||||||
private MoneroWalletRpc wallet;
|
private MoneroWalletRpc wallet;
|
||||||
private Object walletLock = new Object();
|
private Object walletLock = new Object();
|
||||||
@ -364,6 +367,45 @@ public class XmrWalletService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thaw all outputs not reserved for a trade.
|
||||||
|
*/
|
||||||
|
public void thawUnreservedOutputs() {
|
||||||
|
synchronized (walletLock) {
|
||||||
|
|
||||||
|
// collect reserved outputs
|
||||||
|
Set<String> reservedKeyImages = new HashSet<String>();
|
||||||
|
for (Trade trade : tradeManager.getObservableList()) {
|
||||||
|
if (trade.getSelf().getReserveTxKeyImages() == null) continue;
|
||||||
|
reservedKeyImages.addAll(trade.getSelf().getReserveTxKeyImages());
|
||||||
|
}
|
||||||
|
for (OpenOffer openOffer : tradeManager.getOpenOfferManager().getObservableList()) {
|
||||||
|
if (openOffer.getOffer().getOfferPayload().getReserveTxKeyImages() == null) continue;
|
||||||
|
reservedKeyImages.addAll(openOffer.getOffer().getOfferPayload().getReserveTxKeyImages());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure wallet is open
|
||||||
|
if (wallet == null) {
|
||||||
|
log.warn("Cannot thaw unreserved outputs because wallet not open");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// thaw unreserved outputs
|
||||||
|
Set<String> unreservedFrozenKeyImages = wallet.getOutputs(new MoneroOutputQuery()
|
||||||
|
.setIsFrozen(true)
|
||||||
|
.setIsSpent(false))
|
||||||
|
.stream()
|
||||||
|
.map(output -> output.getKeyImage().getHex())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
unreservedFrozenKeyImages.removeAll(reservedKeyImages);
|
||||||
|
if (!unreservedFrozenKeyImages.isEmpty()) {
|
||||||
|
log.warn("Thawing outputs which are not reserved for offer or trade: " + unreservedFrozenKeyImages);
|
||||||
|
thawOutputs(unreservedFrozenKeyImages);
|
||||||
|
saveMainWallet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thaw the given outputs with a lock on the wallet.
|
* Thaw the given outputs with a lock on the wallet.
|
||||||
*
|
*
|
||||||
@ -695,17 +737,21 @@ public class XmrWalletService {
|
|||||||
HavenoUtils.submitToThread(() -> onConnectionChanged(connection), THREAD_ID);
|
HavenoUtils.submitToThread(() -> onConnectionChanged(connection), THREAD_ID);
|
||||||
});
|
});
|
||||||
|
|
||||||
// wait for monerod to sync
|
// initialize main wallet when daemon synced
|
||||||
if (xmrConnectionService.downloadPercentageProperty().get() != 1) {
|
walletInitListener = (obs, oldVal, newVal) -> initMainWalletIfConnected();
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
xmrConnectionService.downloadPercentageProperty().addListener(walletInitListener);
|
||||||
xmrConnectionService.downloadPercentageProperty().addListener((obs, oldVal, newVal) -> {
|
initMainWalletIfConnected();
|
||||||
if (xmrConnectionService.downloadPercentageProperty().get() == 1) latch.countDown();
|
}
|
||||||
});
|
|
||||||
HavenoUtils.awaitLatch(latch);
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize main wallet
|
private void initMainWalletIfConnected() {
|
||||||
maybeInitMainWallet(true);
|
HavenoUtils.submitToThread(() -> {
|
||||||
|
synchronized (walletLock) {
|
||||||
|
if (xmrConnectionService.downloadPercentageProperty().get() == 1 && wallet == null && !isShutDownStarted) {
|
||||||
|
maybeInitMainWallet(true);
|
||||||
|
if (walletInitListener != null) xmrConnectionService.downloadPercentageProperty().removeListener(walletInitListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, THREAD_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeInitMainWallet(boolean sync) {
|
private void maybeInitMainWallet(boolean sync) {
|
||||||
|
Loading…
Reference in New Issue
Block a user