mirror of
https://github.com/boldsuck/haveno.git
synced 2025-01-09 17:49:24 +00:00
trade initialization defers opening and syncing wallet if idling
This commit is contained in:
parent
7ca3b8cee1
commit
a408b0e7ae
2 changed files with 62 additions and 59 deletions
|
@ -517,6 +517,7 @@ public class XmrWalletService {
|
||||||
if (wallet != null) {
|
if (wallet != null) {
|
||||||
try {
|
try {
|
||||||
wallet.sync(); // blocking
|
wallet.sync(); // blocking
|
||||||
|
wallet.startSyncing(connectionsService.getDefaultRefreshPeriodMs()); // start syncing wallet in background
|
||||||
connectionsService.doneDownload(); // TODO: using this to signify both daemon and wallet synced, refactor sync handling of both
|
connectionsService.doneDownload(); // TODO: using this to signify both daemon and wallet synced, refactor sync handling of both
|
||||||
saveWallet(wallet);
|
saveWallet(wallet);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -548,11 +549,11 @@ public class XmrWalletService {
|
||||||
// must be connected to daemon
|
// must be connected to daemon
|
||||||
MoneroRpcConnection connection = connectionsService.getConnection();
|
MoneroRpcConnection connection = connectionsService.getConnection();
|
||||||
if (connection == null || !Boolean.TRUE.equals(connection.isConnected())) throw new RuntimeException("Must be connected to daemon before creating wallet");
|
if (connection == null || !Boolean.TRUE.equals(connection.isConnected())) throw new RuntimeException("Must be connected to daemon before creating wallet");
|
||||||
|
config.setServer(connection);
|
||||||
|
|
||||||
// create wallet
|
// create wallet
|
||||||
try {
|
try {
|
||||||
log.info("Creating wallet " + config.getPath());
|
log.info("Creating wallet " + config.getPath());
|
||||||
MoneroRpcConnection daemonConnection = config.getServer();
|
|
||||||
if (!sync) config.setServer(null);
|
if (!sync) config.setServer(null);
|
||||||
walletRpc.createWallet(config);
|
walletRpc.createWallet(config);
|
||||||
if (sync) {
|
if (sync) {
|
||||||
|
@ -560,7 +561,7 @@ public class XmrWalletService {
|
||||||
walletRpc.startSyncing(connectionsService.getDefaultRefreshPeriodMs());
|
walletRpc.startSyncing(connectionsService.getDefaultRefreshPeriodMs());
|
||||||
log.info("Done starting background sync for wallet " + config.getPath());
|
log.info("Done starting background sync for wallet " + config.getPath());
|
||||||
} else {
|
} else {
|
||||||
walletRpc.setDaemonConnection(daemonConnection);
|
walletRpc.setDaemonConnection(connection);
|
||||||
}
|
}
|
||||||
log.info("Done creating wallet " + config.getPath());
|
log.info("Done creating wallet " + config.getPath());
|
||||||
return walletRpc;
|
return walletRpc;
|
||||||
|
@ -578,21 +579,9 @@ public class XmrWalletService {
|
||||||
|
|
||||||
// open wallet
|
// open wallet
|
||||||
try {
|
try {
|
||||||
// open wallet
|
|
||||||
log.info("Opening wallet " + config.getPath());
|
log.info("Opening wallet " + config.getPath());
|
||||||
walletRpc.openWallet(config);
|
walletRpc.openWallet(config);
|
||||||
|
walletRpc.setDaemonConnection(connectionsService.getConnection());
|
||||||
// sync wallet
|
|
||||||
log.info("Syncing wallet " + config.getPath());
|
|
||||||
walletRpc.sync();
|
|
||||||
log.info("Done syncing wallet " + config.getPath());
|
|
||||||
|
|
||||||
// start syncing wallet in background
|
|
||||||
new Thread(() -> {
|
|
||||||
log.info("Starting background syncing for wallet " + config.getPath());
|
|
||||||
walletRpc.startSyncing(connectionsService.getDefaultRefreshPeriodMs());
|
|
||||||
log.info("Done starting background sync for wallet " + config.getPath());
|
|
||||||
}).start();
|
|
||||||
return walletRpc;
|
return walletRpc;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
|
@ -75,6 +75,7 @@ import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
@ -373,7 +374,7 @@ public abstract class Trade implements Tradable, Model {
|
||||||
transient final private StringProperty errorMessageProperty = new SimpleStringProperty();
|
transient final private StringProperty errorMessageProperty = new SimpleStringProperty();
|
||||||
transient private Subscription tradePhaseSubscription;
|
transient private Subscription tradePhaseSubscription;
|
||||||
transient private Subscription payoutStateSubscription;
|
transient private Subscription payoutStateSubscription;
|
||||||
transient private TaskLooper tradeTxsLooper;
|
transient private TaskLooper txPollLooper;
|
||||||
transient private Long walletRefreshPeriod;
|
transient private Long walletRefreshPeriod;
|
||||||
transient private Long syncNormalStartTime;
|
transient private Long syncNormalStartTime;
|
||||||
private static final long IDLE_SYNC_PERIOD_MS = 3600000; // 1 hour
|
private static final long IDLE_SYNC_PERIOD_MS = 3600000; // 1 hour
|
||||||
|
@ -585,10 +586,7 @@ public abstract class Trade implements Tradable, Model {
|
||||||
// handle trade state events
|
// handle trade state events
|
||||||
tradePhaseSubscription = EasyBind.subscribe(phaseProperty, newValue -> {
|
tradePhaseSubscription = EasyBind.subscribe(phaseProperty, newValue -> {
|
||||||
if (!isInitialized) return;
|
if (!isInitialized) return;
|
||||||
if (isDepositPublished() && !isPayoutUnlocked()) {
|
if (isDepositPublished() && !isPayoutUnlocked()) updateWalletRefreshPeriod();
|
||||||
updateWalletRefreshPeriod();
|
|
||||||
listenToTradeTxs();
|
|
||||||
}
|
|
||||||
if (isCompleted()) {
|
if (isCompleted()) {
|
||||||
UserThread.execute(() -> {
|
UserThread.execute(() -> {
|
||||||
if (tradePhaseSubscription != null) {
|
if (tradePhaseSubscription != null) {
|
||||||
|
@ -620,9 +618,9 @@ public abstract class Trade implements Tradable, Model {
|
||||||
if (newValue == Trade.PayoutState.PAYOUT_UNLOCKED) {
|
if (newValue == Trade.PayoutState.PAYOUT_UNLOCKED) {
|
||||||
log.info("Payout unlocked for {} {}, deleting multisig wallet", getClass().getSimpleName(), getId()); // TODO: retain backup for some time?
|
log.info("Payout unlocked for {} {}, deleting multisig wallet", getClass().getSimpleName(), getId()); // TODO: retain backup for some time?
|
||||||
deleteWallet();
|
deleteWallet();
|
||||||
if (tradeTxsLooper != null) {
|
if (txPollLooper != null) {
|
||||||
tradeTxsLooper.stop();
|
txPollLooper.stop();
|
||||||
tradeTxsLooper = null;
|
txPollLooper = null;
|
||||||
}
|
}
|
||||||
UserThread.execute(() -> {
|
UserThread.execute(() -> {
|
||||||
if (payoutStateSubscription != null) {
|
if (payoutStateSubscription != null) {
|
||||||
|
@ -637,8 +635,7 @@ public abstract class Trade implements Tradable, Model {
|
||||||
|
|
||||||
// start listening to trade wallet
|
// start listening to trade wallet
|
||||||
if (isDepositPublished()) {
|
if (isDepositPublished()) {
|
||||||
updateWalletRefreshPeriod();
|
updateSyncing();
|
||||||
listenToTradeTxs();
|
|
||||||
|
|
||||||
// allow state notifications to process before returning
|
// allow state notifications to process before returning
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
@ -914,10 +911,15 @@ public abstract class Trade implements Tradable, Model {
|
||||||
log.warn("Cannot sync multisig wallet because it doesn't exist for {}, {}", getClass().getSimpleName(), getId());
|
log.warn("Cannot sync multisig wallet because it doesn't exist for {}, {}", getClass().getSimpleName(), getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (getWallet().getDaemonConnection() == null) {
|
||||||
|
log.warn("Cannot sync multisig wallet because it's not connected to a Monero daemon for {}, {}", getClass().getSimpleName(), getId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
log.info("Syncing wallet for {} {}", getClass().getSimpleName(), getId());
|
log.info("Syncing wallet for {} {}", getClass().getSimpleName(), getId());
|
||||||
getWallet().sync();
|
getWallet().sync();
|
||||||
pollWallet();
|
pollWallet();
|
||||||
log.info("Done syncing wallet for {} {}", getClass().getSimpleName(), getId());
|
log.info("Done syncing wallet for {} {}", getClass().getSimpleName(), getId());
|
||||||
|
updateWalletRefreshPeriod();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void syncWalletNormallyForMs(long syncNormalDuration) {
|
public void syncWalletNormallyForMs(long syncNormalDuration) {
|
||||||
|
@ -939,9 +941,9 @@ public abstract class Trade implements Tradable, Model {
|
||||||
|
|
||||||
public void shutDown() {
|
public void shutDown() {
|
||||||
isInitialized = false;
|
isInitialized = false;
|
||||||
if (tradeTxsLooper != null) {
|
if (txPollLooper != null) {
|
||||||
tradeTxsLooper.stop();
|
txPollLooper.stop();
|
||||||
tradeTxsLooper = null;
|
txPollLooper = null;
|
||||||
}
|
}
|
||||||
if (tradePhaseSubscription != null) tradePhaseSubscription.unsubscribe();
|
if (tradePhaseSubscription != null) tradePhaseSubscription.unsubscribe();
|
||||||
if (payoutStateSubscription != null) payoutStateSubscription.unsubscribe();
|
if (payoutStateSubscription != null) payoutStateSubscription.unsubscribe();
|
||||||
|
@ -1397,14 +1399,44 @@ public abstract class Trade implements Tradable, Model {
|
||||||
return tradeVolumeProperty;
|
return tradeVolumeProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void listenToTradeTxs() {
|
private void setDaemonConnection(MoneroRpcConnection connection) {
|
||||||
if (tradeTxsLooper != null) return;
|
if (getWallet() == null) return;
|
||||||
log.info("Listening for payout tx for {} {}", getClass().getSimpleName(), getId());
|
log.info("Setting daemon connection for trade wallet {}: {}: ", getId() , connection == null ? null : connection.getUri());
|
||||||
|
if (getWallet() != null) getWallet().setDaemonConnection(connection);
|
||||||
|
updateSyncing();
|
||||||
|
}
|
||||||
|
|
||||||
// poll wallet for tx state
|
private void updateSyncing() {
|
||||||
pollWallet();
|
if (!isIdling()) syncWallet();
|
||||||
tradeTxsLooper = new TaskLooper(() -> { pollWallet(); });
|
else {
|
||||||
tradeTxsLooper.start(walletRefreshPeriod);
|
long startSyncingInMs = ThreadLocalRandom.current().nextLong(0, getWalletRefreshPeriod()); // random time to start syncing
|
||||||
|
UserThread.runAfter(() -> {
|
||||||
|
if (isInitialized) syncWallet();
|
||||||
|
}, startSyncingInMs / 1000l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateWalletRefreshPeriod() {
|
||||||
|
setWalletRefreshPeriod(getWalletRefreshPeriod());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setWalletRefreshPeriod(long walletRefreshPeriod) {
|
||||||
|
if (this.walletRefreshPeriod != null && this.walletRefreshPeriod == walletRefreshPeriod) return;
|
||||||
|
log.info("Setting wallet refresh rate for {} {} to {}", getClass().getSimpleName(), getId(), walletRefreshPeriod);
|
||||||
|
this.walletRefreshPeriod = walletRefreshPeriod;
|
||||||
|
getWallet().startSyncing(getWalletRefreshPeriod()); // TODO (monero-project): wallet rpc waits until last sync period finishes before starting new sync period
|
||||||
|
if (txPollLooper != null) {
|
||||||
|
txPollLooper.stop();
|
||||||
|
txPollLooper = null;
|
||||||
|
}
|
||||||
|
startPolling();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startPolling() {
|
||||||
|
if (txPollLooper != null) return;
|
||||||
|
log.info("Listening for payout tx for {} {}", getClass().getSimpleName(), getId());
|
||||||
|
txPollLooper = new TaskLooper(() -> { pollWallet(); });
|
||||||
|
txPollLooper.start(walletRefreshPeriod);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pollWallet() {
|
private void pollWallet() {
|
||||||
|
@ -1462,32 +1494,14 @@ public abstract class Trade implements Tradable, Model {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDaemonConnection(MoneroRpcConnection connection) {
|
|
||||||
if (getWallet() == null) return;
|
|
||||||
log.info("Setting daemon connection for trade wallet {}: {}: ", getId() , connection == null ? null : connection.getUri());
|
|
||||||
getWallet().setDaemonConnection(connection);
|
|
||||||
updateWalletRefreshPeriod();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateWalletRefreshPeriod() {
|
|
||||||
setWalletRefreshPeriod(getWalletRefreshPeriod());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setWalletRefreshPeriod(long walletRefreshPeriod) {
|
|
||||||
if (this.walletRefreshPeriod != null && this.walletRefreshPeriod == walletRefreshPeriod) return;
|
|
||||||
log.info("Setting wallet refresh rate for {} {} to {}", getClass().getSimpleName(), getId(), walletRefreshPeriod);
|
|
||||||
this.walletRefreshPeriod = walletRefreshPeriod;
|
|
||||||
getWallet().startSyncing(getWalletRefreshPeriod()); // TODO (monero-project): wallet rpc waits until last sync period finishes before starting new sync period
|
|
||||||
if (tradeTxsLooper != null) {
|
|
||||||
tradeTxsLooper.stop();
|
|
||||||
tradeTxsLooper = null;
|
|
||||||
listenToTradeTxs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getWalletRefreshPeriod() {
|
private long getWalletRefreshPeriod() {
|
||||||
if (this instanceof ArbitratorTrade && isDepositConfirmed()) return IDLE_SYNC_PERIOD_MS; // slow arbitrator trade wallet after deposits confirm
|
if (isIdling()) return IDLE_SYNC_PERIOD_MS;
|
||||||
return xmrWalletService.getConnectionsService().getDefaultRefreshPeriodMs(); // else sync at default rate
|
return xmrWalletService.getConnectionsService().getDefaultRefreshPeriodMs();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIdling() {
|
||||||
|
return this instanceof ArbitratorTrade && isDepositConfirmed(); // arbitrator idles after deposits confirm
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setStateDepositsPublished() {
|
private void setStateDepositsPublished() {
|
||||||
|
|
Loading…
Reference in a new issue