mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-12-22 11:39:29 +00:00
monero wallets switch to tor after initial sync by default
This commit is contained in:
parent
0620bf260e
commit
f19bc2ad4b
20 changed files with 276 additions and 129 deletions
|
@ -137,6 +137,12 @@ public class Config {
|
|||
public final boolean helpRequested;
|
||||
public final File configFile;
|
||||
|
||||
public enum UseTorForXmr {
|
||||
AFTER_SYNC,
|
||||
OFF,
|
||||
ON
|
||||
}
|
||||
|
||||
// Options supported on cmd line and in the config file
|
||||
public final String appName;
|
||||
public final File userDataDir;
|
||||
|
@ -180,7 +186,7 @@ public class Config {
|
|||
public final String xmrNodeUsername;
|
||||
public final String xmrNodePassword;
|
||||
public final String xmrNodes;
|
||||
public final boolean useTorForXmr;
|
||||
public final UseTorForXmr useTorForXmr;
|
||||
public final boolean useTorForXmrOptionSetExplicitly;
|
||||
public final String socks5DiscoverMode;
|
||||
public final boolean useAllProvidedNodes;
|
||||
|
@ -514,16 +520,18 @@ public class Config {
|
|||
.defaultsTo("");
|
||||
|
||||
ArgumentAcceptingOptionSpec<String> xmrNodesOpt =
|
||||
parser.accepts(XMR_NODES, "Custom nodes used for BitcoinJ as comma separated IP addresses.")
|
||||
parser.accepts(XMR_NODES, "Custom nodes used for Monero as comma separated IP addresses.")
|
||||
.withRequiredArg()
|
||||
.describedAs("ip[,...]")
|
||||
.defaultsTo("");
|
||||
|
||||
ArgumentAcceptingOptionSpec<Boolean> useTorForXmrOpt =
|
||||
parser.accepts(USE_TOR_FOR_XMR, "If set to true BitcoinJ is routed over tor (socks 5 proxy).")
|
||||
//noinspection rawtypes
|
||||
ArgumentAcceptingOptionSpec<Enum> useTorForXmrOpt =
|
||||
parser.accepts(USE_TOR_FOR_XMR, "Configure TOR for Monero connections, one of: after_sync, off, or on.")
|
||||
.withRequiredArg()
|
||||
.ofType(Boolean.class)
|
||||
.defaultsTo(false);
|
||||
.ofType(UseTorForXmr.class)
|
||||
.withValuesConvertedBy(new EnumValueConverter(UseTorForXmr.class))
|
||||
.defaultsTo(UseTorForXmr.AFTER_SYNC);
|
||||
|
||||
ArgumentAcceptingOptionSpec<String> socks5DiscoverModeOpt =
|
||||
parser.accepts(SOCKS5_DISCOVER_MODE, "Specify discovery mode for Bitcoin nodes. " +
|
||||
|
@ -686,7 +694,7 @@ public class Config {
|
|||
this.xmrNodeUsername = options.valueOf(xmrNodeUsernameOpt);
|
||||
this.xmrNodePassword = options.valueOf(xmrNodePasswordOpt);
|
||||
this.xmrNodes = options.valueOf(xmrNodesOpt);
|
||||
this.useTorForXmr = options.valueOf(useTorForXmrOpt);
|
||||
this.useTorForXmr = (UseTorForXmr) options.valueOf(useTorForXmrOpt);
|
||||
this.useTorForXmrOptionSetExplicitly = options.has(useTorForXmrOpt);
|
||||
this.socks5DiscoverMode = options.valueOf(socks5DiscoverModeOpt);
|
||||
this.useAllProvidedNodes = options.valueOf(useAllProvidedNodesOpt);
|
||||
|
|
|
@ -333,7 +333,7 @@ public final class CoreMoneroConnectionsService {
|
|||
}
|
||||
|
||||
private boolean useProxy(MoneroRpcConnection connection) {
|
||||
return connection.isOnion() || (preferences.isUseTorForMonero() && !HavenoUtils.isLocalHost(connection.getUri()));
|
||||
return connection.isOnion() || (preferences.getUseTorForXmr().isUseTorForXmr() && !HavenoUtils.isLocalHost(connection.getUri()));
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
|
|
|
@ -49,6 +49,7 @@ import haveno.core.trade.TradeManager;
|
|||
import haveno.core.trade.TradeTxException;
|
||||
import haveno.core.user.Preferences;
|
||||
import haveno.core.user.User;
|
||||
import haveno.core.user.Preferences.UseTorForXmr;
|
||||
import haveno.core.util.FormattingUtils;
|
||||
import haveno.core.util.coin.CoinFormatter;
|
||||
import haveno.core.xmr.model.AddressEntry;
|
||||
|
@ -63,6 +64,7 @@ import haveno.network.p2p.storage.payload.PersistableNetworkPayload;
|
|||
import haveno.network.utils.Utils;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
|
@ -725,8 +727,8 @@ public class HavenoSetup {
|
|||
return walletAppSetup.getXmrSplashSyncIconId();
|
||||
}
|
||||
|
||||
public BooleanProperty getUseTorForXMR() {
|
||||
return walletAppSetup.getUseTorForXMR();
|
||||
public ObjectProperty<UseTorForXmr> getUseTorForXmr() {
|
||||
return walletAppSetup.getUseTorForXmr();
|
||||
}
|
||||
|
||||
// P2P
|
||||
|
|
|
@ -25,15 +25,14 @@ import haveno.core.locale.Res;
|
|||
import haveno.core.offer.OpenOfferManager;
|
||||
import haveno.core.trade.TradeManager;
|
||||
import haveno.core.user.Preferences;
|
||||
import haveno.core.user.Preferences.UseTorForXmr;
|
||||
import haveno.core.util.FormattingUtils;
|
||||
import haveno.core.xmr.exceptions.InvalidHostException;
|
||||
import haveno.core.xmr.exceptions.RejectedTxException;
|
||||
import haveno.core.xmr.setup.WalletsSetup;
|
||||
import haveno.core.xmr.wallet.WalletsManager;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
|
@ -80,7 +79,7 @@ public class WalletAppSetup {
|
|||
@Getter
|
||||
private final ObjectProperty<RejectedTxException> rejectedTxException = new SimpleObjectProperty<>();
|
||||
@Getter
|
||||
private final BooleanProperty useTorForXMR = new SimpleBooleanProperty();
|
||||
private final ObjectProperty<UseTorForXmr> useTorForXmr = new SimpleObjectProperty<UseTorForXmr>();
|
||||
|
||||
@Inject
|
||||
public WalletAppSetup(CoreContext coreContext,
|
||||
|
@ -95,7 +94,7 @@ public class WalletAppSetup {
|
|||
this.connectionService = connectionService;
|
||||
this.config = config;
|
||||
this.preferences = preferences;
|
||||
this.useTorForXMR.set(preferences.getUseTorForMonero());
|
||||
this.useTorForXmr.set(preferences.getUseTorForXmr());
|
||||
}
|
||||
|
||||
void init(@Nullable Consumer<String> chainFileLockedExceptionHandler,
|
||||
|
@ -239,7 +238,7 @@ public class WalletAppSetup {
|
|||
String postFix;
|
||||
if (config.ignoreLocalXmrNode)
|
||||
postFix = " " + Res.get("mainView.footer.localhostBitcoinNode");
|
||||
else if (preferences.getUseTorForMonero())
|
||||
else if (preferences.getUseTorForXmr().isUseTorForXmr())
|
||||
postFix = " " + Res.get("mainView.footer.usingTor");
|
||||
else
|
||||
postFix = "";
|
||||
|
|
|
@ -838,7 +838,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
trade.importMultisigHex();
|
||||
|
||||
// sync and save wallet
|
||||
trade.syncWallet();
|
||||
trade.syncAndPollWallet();
|
||||
trade.saveWallet();
|
||||
|
||||
// create unsigned dispute payout tx if not already published
|
||||
|
@ -887,7 +887,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
trade.getSelf().setUpdatedMultisigHex(trade.getWallet().exportMultisigHex());
|
||||
return payoutTx;
|
||||
} catch (Exception e) {
|
||||
trade.syncWallet();
|
||||
trade.syncAndPollWallet();
|
||||
if (!trade.isPayoutPublished()) throw e;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -249,7 +249,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
|
||||
// sync and save wallet
|
||||
if (!trade.isPayoutPublished()) {
|
||||
trade.syncWallet();
|
||||
trade.syncAndPollWallet();
|
||||
trade.saveWallet();
|
||||
}
|
||||
|
||||
|
@ -266,7 +266,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
if (disputeClosedMessage.isDeferPublishPayout()) {
|
||||
log.info("Deferring signing and publishing dispute payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId());
|
||||
GenUtils.waitFor(Trade.DEFER_PUBLISH_MS);
|
||||
if (!trade.isPayoutUnlocked()) trade.syncWallet();
|
||||
if (!trade.isPayoutUnlocked()) trade.syncAndPollWallet();
|
||||
}
|
||||
|
||||
// sign and publish dispute payout tx if peer still has not published
|
||||
|
@ -277,7 +277,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
} catch (Exception e) {
|
||||
|
||||
// check if payout published again
|
||||
trade.syncWallet();
|
||||
trade.syncAndPollWallet();
|
||||
if (trade.isPayoutPublished()) {
|
||||
log.info("Dispute payout tx already published for {} {}", trade.getClass().getSimpleName(), trade.getId());
|
||||
} else {
|
||||
|
|
|
@ -111,6 +111,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
private static final String MONERO_TRADE_WALLET_PREFIX = "xmr_trade_";
|
||||
private MoneroWallet wallet; // trade wallet
|
||||
private Object walletLock = new Object();
|
||||
boolean wasWalletSynced = false;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Enums
|
||||
|
@ -382,6 +383,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
transient final private ObjectProperty<DisputeState> disputeStateProperty = new SimpleObjectProperty<>(disputeState);
|
||||
transient final private ObjectProperty<TradePeriodState> tradePeriodStateProperty = new SimpleObjectProperty<>(periodState);
|
||||
transient final private StringProperty errorMessageProperty = new SimpleStringProperty();
|
||||
transient private Subscription tradeStateSubscription;
|
||||
transient private Subscription tradePhaseSubscription;
|
||||
transient private Subscription payoutStateSubscription;
|
||||
transient private TaskLooper txPollLooper;
|
||||
|
@ -602,6 +604,14 @@ public abstract class Trade implements Tradable, Model {
|
|||
setState(Trade.State.BUYER_SENT_PAYMENT_SENT_MSG);
|
||||
}
|
||||
|
||||
// handle trade state events
|
||||
tradeStateSubscription = EasyBind.subscribe(stateProperty, newValue -> {
|
||||
if (newValue == Trade.State.MULTISIG_COMPLETED) {
|
||||
updateWalletRefreshPeriod();
|
||||
startPolling();
|
||||
}
|
||||
});
|
||||
|
||||
// handle trade phase events
|
||||
tradePhaseSubscription = EasyBind.subscribe(phaseProperty, newValue -> {
|
||||
if (isDepositsPublished() && !isPayoutUnlocked()) updateWalletRefreshPeriod();
|
||||
|
@ -615,7 +625,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
}
|
||||
});
|
||||
|
||||
// handle payout state events
|
||||
// handle payout events
|
||||
payoutStateSubscription = EasyBind.subscribe(payoutStateProperty, newValue -> {
|
||||
if (isPayoutPublished()) updateWalletRefreshPeriod();
|
||||
|
||||
|
@ -657,15 +667,13 @@ public abstract class Trade implements Tradable, Model {
|
|||
xmrWalletService.addWalletListener(idlePayoutSyncer);
|
||||
}
|
||||
|
||||
// reprocess pending payout messages
|
||||
this.getProtocol().maybeReprocessPaymentReceivedMessage(false);
|
||||
HavenoUtils.arbitrationManager.maybeReprocessDisputeClosedMessage(this, false);
|
||||
|
||||
// trade is initialized but not synced
|
||||
// trade is initialized
|
||||
isInitialized = true;
|
||||
|
||||
// sync wallet if applicable
|
||||
// done if payout unlocked or deposit not requested
|
||||
if (!isDepositRequested() || isPayoutUnlocked()) return;
|
||||
|
||||
// done if wallet does not exist
|
||||
if (!walletExists()) {
|
||||
MoneroTx payoutTx = getPayoutTx();
|
||||
if (payoutTx != null && payoutTx.getNumConfirmations() >= 10) {
|
||||
|
@ -676,8 +684,9 @@ public abstract class Trade implements Tradable, Model {
|
|||
throw new IllegalStateException("Missing trade wallet for " + getClass().getSimpleName() + " " + getId());
|
||||
}
|
||||
}
|
||||
if (xmrWalletService.getConnectionsService().getConnection() == null || Boolean.FALSE.equals(xmrWalletService.getConnectionsService().isConnected())) return;
|
||||
updateSyncing();
|
||||
|
||||
// initialize syncing and polling
|
||||
initSyncing();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -726,7 +735,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
if (wallet != null) return wallet;
|
||||
if (!walletExists()) return null;
|
||||
if (isShutDownStarted) throw new RuntimeException("Cannot open wallet for " + getClass().getSimpleName() + " " + getId() + " because shut down is started");
|
||||
else wallet = xmrWalletService.openWallet(getWalletName());
|
||||
else wallet = xmrWalletService.openWallet(getWalletName(), xmrWalletService.isProxyApplied(wasWalletSynced));
|
||||
return wallet;
|
||||
}
|
||||
}
|
||||
|
@ -755,23 +764,8 @@ public abstract class Trade implements Tradable, Model {
|
|||
return this instanceof ArbitratorTrade && isDepositsConfirmed() && walletExists(); // arbitrator idles trade after deposits confirm
|
||||
}
|
||||
|
||||
public void syncWallet() {
|
||||
if (getWallet() == null) throw new RuntimeException("Cannot sync trade wallet because it doesn't exist for " + getClass().getSimpleName() + ", " + getId());
|
||||
if (getWallet().getDaemonConnection() == null) throw new RuntimeException("Cannot sync trade wallet because it's not connected to a Monero daemon for " + getClass().getSimpleName() + ", " + getId());
|
||||
log.info("Syncing wallet for {} {}", getClass().getSimpleName(), getId());
|
||||
xmrWalletService.syncWallet(getWallet());
|
||||
pollWallet();
|
||||
log.info("Done syncing wallet for {} {}", getClass().getSimpleName(), getId());
|
||||
}
|
||||
|
||||
private void trySyncWallet() {
|
||||
try {
|
||||
syncWallet();
|
||||
} catch (Exception e) {
|
||||
if (!isShutDown && walletExists()) {
|
||||
log.warn("Error syncing trade wallet for {} {}: {}", getClass().getSimpleName(), getId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
public void syncAndPollWallet() {
|
||||
syncWallet(true);
|
||||
}
|
||||
|
||||
public void syncWalletNormallyForMs(long syncNormalDuration) {
|
||||
|
@ -1148,6 +1142,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
stopWallet();
|
||||
}
|
||||
}
|
||||
if (tradeStateSubscription != null) tradeStateSubscription.unsubscribe();
|
||||
if (tradePhaseSubscription != null) tradePhaseSubscription.unsubscribe();
|
||||
if (payoutStateSubscription != null) payoutStateSubscription.unsubscribe();
|
||||
idlePayoutSyncer = null; // main wallet removes listener itself
|
||||
|
@ -1697,44 +1692,76 @@ public abstract class Trade implements Tradable, Model {
|
|||
// set daemon connection (must restart monero-wallet-rpc if proxy uri changed)
|
||||
String oldProxyUri = wallet.getDaemonConnection() == null ? null : wallet.getDaemonConnection().getProxyUri();
|
||||
String newProxyUri = connection == null ? null : connection.getProxyUri();
|
||||
log.info("Setting daemon connection for trade wallet {}: {}", getId() , connection == null ? null : connection.getUri());
|
||||
if (wallet instanceof MoneroWalletRpc && !StringUtils.equals(oldProxyUri, newProxyUri)) {
|
||||
log.info("Restarting monero-wallet-rpc for trade wallet to set proxy URI {}: {}", getId() , connection == null ? null : connection.getUri());
|
||||
log.info("Setting daemon connection for trade wallet {}: uri={}, proxyUri={}", getId() , connection == null ? null : connection.getUri(), newProxyUri);
|
||||
if (xmrWalletService.isProxyApplied(wasWalletSynced) && wallet instanceof MoneroWalletRpc && !StringUtils.equals(oldProxyUri, newProxyUri)) {
|
||||
log.info("Restarting trade wallet {} because proxy URI has changed, old={}, new={}", getId(), oldProxyUri, newProxyUri);
|
||||
closeWallet();
|
||||
wallet = getWallet();
|
||||
} else {
|
||||
wallet.setDaemonConnection(connection);
|
||||
}
|
||||
updateWalletRefreshPeriod();
|
||||
|
||||
// sync and reprocess messages on new thread
|
||||
if (connection != null && !Boolean.FALSE.equals(connection.isConnected())) {
|
||||
if (isInitialized && connection != null && !Boolean.FALSE.equals(connection.isConnected())) {
|
||||
HavenoUtils.submitTask(() -> {
|
||||
updateSyncing();
|
||||
|
||||
// reprocess pending payout messages
|
||||
this.getProtocol().maybeReprocessPaymentReceivedMessage(false);
|
||||
HavenoUtils.arbitrationManager.maybeReprocessDisputeClosedMessage(this, false);
|
||||
initSyncing();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSyncing() {
|
||||
private void initSyncing() {
|
||||
if (isShutDownStarted) return;
|
||||
if (!isIdling()) {
|
||||
updateWalletRefreshPeriod();
|
||||
trySyncWallet();
|
||||
initSyncingAux();
|
||||
} else {
|
||||
long startSyncingInMs = ThreadLocalRandom.current().nextLong(0, getWalletRefreshPeriod()); // random time to start syncing
|
||||
UserThread.runAfter(() -> {
|
||||
if (!isShutDownStarted) {
|
||||
updateWalletRefreshPeriod();
|
||||
trySyncWallet();
|
||||
initSyncingAux();
|
||||
}
|
||||
}, startSyncingInMs / 1000l);
|
||||
}
|
||||
}
|
||||
|
||||
private void initSyncingAux() {
|
||||
if (!wasWalletSynced) trySyncWallet(false);
|
||||
updateWalletRefreshPeriod();
|
||||
|
||||
// reprocess pending payout messages
|
||||
this.getProtocol().maybeReprocessPaymentReceivedMessage(false);
|
||||
HavenoUtils.arbitrationManager.maybeReprocessDisputeClosedMessage(this, false);
|
||||
|
||||
startPolling();
|
||||
}
|
||||
|
||||
private void trySyncWallet(boolean pollWallet) {
|
||||
try {
|
||||
syncWallet(pollWallet);
|
||||
} catch (Exception e) {
|
||||
if (!isShutDown && walletExists()) {
|
||||
log.warn("Error syncing trade wallet for {} {}: {}", getClass().getSimpleName(), getId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void syncWallet(boolean pollWallet) {
|
||||
if (getWallet() == null) throw new RuntimeException("Cannot sync trade wallet because it doesn't exist for " + getClass().getSimpleName() + ", " + getId());
|
||||
if (getWallet().getDaemonConnection() == null) throw new RuntimeException("Cannot sync trade wallet because it's not connected to a Monero daemon for " + getClass().getSimpleName() + ", " + getId());
|
||||
log.info("Syncing wallet for {} {}", getClass().getSimpleName(), getId());
|
||||
xmrWalletService.syncWallet(getWallet());
|
||||
log.info("Done syncing wallet for {} {}", getClass().getSimpleName(), getId());
|
||||
|
||||
// apply tor after wallet synced depending on configuration
|
||||
if (!wasWalletSynced) {
|
||||
wasWalletSynced = true;
|
||||
if (xmrWalletService.isProxyApplied(wasWalletSynced)) {
|
||||
onConnectionChanged(xmrWalletService.getConnectionsService().getConnection());
|
||||
}
|
||||
}
|
||||
|
||||
if (pollWallet) pollWallet();
|
||||
}
|
||||
|
||||
public void updateWalletRefreshPeriod() {
|
||||
setWalletRefreshPeriod(getWalletRefreshPeriod());
|
||||
|
@ -1749,14 +1776,16 @@ public abstract class Trade implements Tradable, Model {
|
|||
log.info("Setting wallet refresh rate for {} {} to {}", getClass().getSimpleName(), getId(), walletRefreshPeriod);
|
||||
getWallet().startSyncing(getWalletRefreshPeriod()); // TODO (monero-project): wallet rpc waits until last sync period finishes before starting new sync period
|
||||
}
|
||||
stopPolling();
|
||||
if (isPolling()) {
|
||||
stopPolling();
|
||||
startPolling();
|
||||
}
|
||||
}
|
||||
startPolling();
|
||||
}
|
||||
|
||||
private void startPolling() {
|
||||
synchronized (walletLock) {
|
||||
if (txPollLooper != null) return;
|
||||
if (isPolling()) return;
|
||||
log.info("Starting to poll wallet for {} {}", getClass().getSimpleName(), getId());
|
||||
txPollLooper = new TaskLooper(() -> pollWallet());
|
||||
txPollLooper.start(walletRefreshPeriod);
|
||||
|
@ -1765,12 +1794,18 @@ public abstract class Trade implements Tradable, Model {
|
|||
|
||||
private void stopPolling() {
|
||||
synchronized (walletLock) {
|
||||
if (txPollLooper != null) {
|
||||
if (isPolling()) {
|
||||
txPollLooper.stop();
|
||||
txPollLooper = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPolling() {
|
||||
synchronized (walletLock) {
|
||||
return txPollLooper != null;
|
||||
}
|
||||
}
|
||||
|
||||
private void pollWallet() {
|
||||
try {
|
||||
|
@ -1855,7 +1890,6 @@ public abstract class Trade implements Tradable, Model {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private long getWalletRefreshPeriod() {
|
||||
if (isIdling()) return IDLE_SYNC_PERIOD_MS;
|
||||
return xmrWalletService.getConnectionsService().getRefreshPeriodMs();
|
||||
|
@ -1924,7 +1958,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
long currentHeight = xmrWalletService.getDaemon().getHeight();
|
||||
if (!isPayoutConfirmed() || (payoutHeight != null && currentHeight >= payoutHeight + XmrWalletService.NUM_BLOCKS_UNLOCK)) {
|
||||
log.info("Syncing idle trade wallet to update payout tx, tradeId={}", getId());
|
||||
syncWallet();
|
||||
syncAndPollWallet();
|
||||
}
|
||||
processing = false;
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -449,7 +449,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
|||
|
||||
// sync idle trades once in background after active trades
|
||||
for (Trade trade : trades) {
|
||||
if (trade.isIdling()) HavenoUtils.submitTask(() -> trade.syncWallet());
|
||||
if (trade.isIdling()) HavenoUtils.submitTask(() -> trade.syncAndPollWallet());
|
||||
}
|
||||
|
||||
// process after all wallets initialized
|
||||
|
|
|
@ -112,7 +112,6 @@ public class ProcessInitMultisigRequest extends TradeTask {
|
|||
processModel.setMultisigAddress(result.getAddress());
|
||||
new Thread(() -> trade.saveWallet()).start(); // save multisig wallet off thread on completion
|
||||
trade.setStateIfValidTransitionTo(Trade.State.MULTISIG_COMPLETED);
|
||||
trade.updateWalletRefreshPeriod(); // starts syncing
|
||||
}
|
||||
|
||||
// update multisig participants if new state to communicate
|
||||
|
|
|
@ -105,7 +105,7 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
|
|||
|
||||
// update wallet
|
||||
trade.importMultisigHex();
|
||||
trade.syncWallet();
|
||||
trade.syncAndPollWallet();
|
||||
trade.saveWallet();
|
||||
|
||||
// handle if payout tx not published
|
||||
|
@ -117,7 +117,7 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
|
|||
if (deferSignAndPublish) {
|
||||
log.info("Deferring signing and publishing payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId());
|
||||
GenUtils.waitFor(Trade.DEFER_PUBLISH_MS);
|
||||
if (!trade.isPayoutUnlocked()) trade.syncWallet();
|
||||
if (!trade.isPayoutUnlocked()) trade.syncAndPollWallet();
|
||||
}
|
||||
|
||||
// verify and publish payout tx
|
||||
|
@ -136,7 +136,7 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
|
|||
trade.verifyPayoutTx(trade.getPayoutTxHex(), false, true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
trade.syncWallet();
|
||||
trade.syncAndPollWallet();
|
||||
if (trade.isPayoutPublished()) log.info("Payout tx already published for {} {}", trade.getClass().getName(), trade.getId());
|
||||
else throw e;
|
||||
}
|
||||
|
|
|
@ -66,6 +66,16 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
@Slf4j
|
||||
@Singleton
|
||||
public final class Preferences implements PersistedDataHost, BridgeAddressProvider {
|
||||
|
||||
public enum UseTorForXmr {
|
||||
AFTER_SYNC,
|
||||
OFF,
|
||||
ON;
|
||||
|
||||
public boolean isUseTorForXmr() {
|
||||
return this != UseTorForXmr.OFF;
|
||||
}
|
||||
}
|
||||
|
||||
private static final ArrayList<BlockChainExplorer> BTC_MAIN_NET_EXPLORERS = new ArrayList<>(Arrays.asList(
|
||||
new BlockChainExplorer("mempool.space (@wiz)", "https://mempool.space/tx/", "https://mempool.space/address/"),
|
||||
|
@ -300,7 +310,7 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||
|
||||
// Override settings with options if set
|
||||
if (config.useTorForXmrOptionSetExplicitly)
|
||||
setUseTorForMonero(config.useTorForXmr);
|
||||
setUseTorForXmr(config.useTorForXmr);
|
||||
|
||||
if (xmrNodesFromOptions != null && !xmrNodesFromOptions.isEmpty()) {
|
||||
if (getMoneroNodes() != null && !getMoneroNodes().equals(xmrNodesFromOptions)) {
|
||||
|
@ -488,9 +498,20 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||
}
|
||||
}
|
||||
|
||||
public void setUseTorForMonero(boolean useTorForMonero) {
|
||||
prefPayload.setUseTorForMonero(useTorForMonero);
|
||||
requestPersistence();
|
||||
public void setUseTorForXmr(Config.UseTorForXmr useTorForXmr) {
|
||||
switch (useTorForXmr) {
|
||||
case AFTER_SYNC:
|
||||
setUseTorForXmrOrdinal(Preferences.UseTorForXmr.AFTER_SYNC.ordinal());
|
||||
break;
|
||||
case OFF:
|
||||
setUseTorForXmrOrdinal(Preferences.UseTorForXmr.OFF.ordinal());
|
||||
break;
|
||||
case ON:
|
||||
setUseTorForXmrOrdinal(Preferences.UseTorForXmr.ON.ordinal());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unexpected case: " + useTorForXmr);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSplitOfferOutput(boolean splitOfferOutput) {
|
||||
|
@ -663,6 +684,11 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||
prefPayload.setCustomBridges(customBridges);
|
||||
persistenceManager.forcePersistNow();
|
||||
}
|
||||
|
||||
public void setUseTorForXmrOrdinal(int useTorForXmrOrdinal) {
|
||||
prefPayload.setUseTorForXmrOrdinal(useTorForXmrOrdinal);
|
||||
requestPersistence();
|
||||
}
|
||||
|
||||
public void setMoneroNodesOptionOrdinal(int bitcoinNodesOptionOrdinal) {
|
||||
prefPayload.setMoneroNodesOptionOrdinal(bitcoinNodesOptionOrdinal);
|
||||
|
@ -794,8 +820,12 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||
return !prefPayload.getDontShowAgainMap().containsKey(key) || !prefPayload.getDontShowAgainMap().get(key);
|
||||
}
|
||||
|
||||
public boolean getUseTorForMonero() {
|
||||
return prefPayload.isUseTorForMonero();
|
||||
public UseTorForXmr getUseTorForXmr() {
|
||||
return UseTorForXmr.class.getEnumConstants()[prefPayload.getUseTorForXmrOrdinal()];
|
||||
}
|
||||
|
||||
public boolean isProxyApplied(boolean wasWalletSynced) {
|
||||
return getUseTorForXmr() == UseTorForXmr.ON || (getUseTorForXmr() == UseTorForXmr.AFTER_SYNC && wasWalletSynced);
|
||||
}
|
||||
|
||||
public boolean getSplitOfferOutput() {
|
||||
|
@ -864,8 +894,6 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||
|
||||
void setPreferredTradeCurrency(TradeCurrency preferredTradeCurrency);
|
||||
|
||||
void setUseTorForMonero(boolean useTorForMonero);
|
||||
|
||||
void setSplitOfferOutput(boolean splitOfferOutput);
|
||||
|
||||
void setShowOwnOffersInOfferBook(boolean showOwnOffersInOfferBook);
|
||||
|
@ -927,6 +955,8 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
|||
void setTorTransportOrdinal(int torTransportOrdinal);
|
||||
|
||||
void setCustomBridges(String customBridges);
|
||||
|
||||
void setUseTorForXmrOrdinal(int useTorForXmrOrdinal);
|
||||
|
||||
void setMoneroNodesOptionOrdinal(int bitcoinNodesOption);
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
private boolean autoSelectArbitrators = true;
|
||||
private Map<String, Boolean> dontShowAgainMap = new HashMap<>();
|
||||
private boolean tacAccepted;
|
||||
private boolean useTorForMonero = false;
|
||||
private boolean splitOfferOutput = false;
|
||||
private boolean showOwnOffersInOfferBook = true;
|
||||
@Nullable
|
||||
|
@ -98,6 +97,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
private int torTransportOrdinal;
|
||||
@Nullable
|
||||
private String customBridges;
|
||||
private int useTorForXmrOrdinal;
|
||||
private int moneroNodesOptionOrdinal;
|
||||
@Nullable
|
||||
private String referralId;
|
||||
|
@ -161,7 +161,6 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
.setAutoSelectArbitrators(autoSelectArbitrators)
|
||||
.putAllDontShowAgainMap(dontShowAgainMap)
|
||||
.setTacAccepted(tacAccepted)
|
||||
.setUseTorForMonero(useTorForMonero)
|
||||
.setSplitOfferOutput(splitOfferOutput)
|
||||
.setShowOwnOffersInOfferBook(showOwnOffersInOfferBook)
|
||||
.setWithdrawalTxFeeInVbytes(withdrawalTxFeeInVbytes)
|
||||
|
@ -179,6 +178,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
.setCssTheme(cssTheme)
|
||||
.setBridgeOptionOrdinal(bridgeOptionOrdinal)
|
||||
.setTorTransportOrdinal(torTransportOrdinal)
|
||||
.setUseTorForXmrOrdinal(useTorForXmrOrdinal)
|
||||
.setMoneroNodesOptionOrdinal(moneroNodesOptionOrdinal)
|
||||
.setUseSoundForMobileNotifications(useSoundForMobileNotifications)
|
||||
.setUseTradeNotifications(useTradeNotifications)
|
||||
|
@ -244,7 +244,6 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
proto.getAutoSelectArbitrators(),
|
||||
Maps.newHashMap(proto.getDontShowAgainMapMap()),
|
||||
proto.getTacAccepted(),
|
||||
proto.getUseTorForMonero(),
|
||||
proto.getSplitOfferOutput(),
|
||||
proto.getShowOwnOffersInOfferBook(),
|
||||
proto.hasPreferredTradeCurrency() ? TradeCurrency.fromProto(proto.getPreferredTradeCurrency()) : null,
|
||||
|
@ -272,6 +271,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
|||
proto.getBridgeOptionOrdinal(),
|
||||
proto.getTorTransportOrdinal(),
|
||||
ProtoUtil.stringOrNullFromProto(proto.getCustomBridges()),
|
||||
proto.getUseTorForXmrOrdinal(),
|
||||
proto.getMoneroNodesOptionOrdinal(),
|
||||
proto.getReferralId().isEmpty() ? null : proto.getReferralId(),
|
||||
proto.getPhoneKeyAndToken().isEmpty() ? null : proto.getPhoneKeyAndToken(),
|
||||
|
|
|
@ -171,7 +171,7 @@ public class WalletsSetup {
|
|||
|
||||
backupWallets();
|
||||
|
||||
final Socks5Proxy socks5Proxy = preferences.getUseTorForMonero() ? socks5ProxyProvider.getSocks5Proxy() : null;
|
||||
final Socks5Proxy socks5Proxy = socks5ProxyProvider.getSocks5Proxy();
|
||||
log.info("Socks5Proxy for bitcoinj: socks5Proxy=" + socks5Proxy);
|
||||
|
||||
walletConfig = new WalletConfig(params, walletDir, "haveno") {
|
||||
|
|
|
@ -19,6 +19,7 @@ import haveno.core.trade.HavenoUtils;
|
|||
import haveno.core.trade.MakerTrade;
|
||||
import haveno.core.trade.Trade;
|
||||
import haveno.core.trade.TradeManager;
|
||||
import haveno.core.user.Preferences;
|
||||
import haveno.core.xmr.listeners.XmrBalanceListener;
|
||||
import haveno.core.xmr.model.XmrAddressEntry;
|
||||
import haveno.core.xmr.model.XmrAddressEntryList;
|
||||
|
@ -54,7 +55,6 @@ import monero.wallet.model.MoneroWalletListenerI;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.math.BigInteger;
|
||||
|
@ -100,6 +100,7 @@ public class XmrWalletService {
|
|||
private static final int MONERO_LOG_LEVEL = 0;
|
||||
private static final boolean PRINT_STACK_TRACE = false;
|
||||
|
||||
private final Preferences preferences;
|
||||
private final CoreAccountService accountService;
|
||||
private final CoreMoneroConnectionsService connectionsService;
|
||||
private final XmrAddressEntryList xmrAddressEntryList;
|
||||
|
@ -114,17 +115,20 @@ public class XmrWalletService {
|
|||
private TradeManager tradeManager;
|
||||
private MoneroWalletRpc wallet;
|
||||
private Object walletLock = new Object();
|
||||
private boolean wasWalletSynced = false;
|
||||
private final Map<String, Optional<MoneroTx>> txCache = new HashMap<String, Optional<MoneroTx>>();
|
||||
private boolean isShutDownStarted = false;
|
||||
private ExecutorService syncWalletThreadPool = Executors.newFixedThreadPool(10); // TODO: adjust based on connection type
|
||||
|
||||
@Inject
|
||||
XmrWalletService(CoreAccountService accountService,
|
||||
XmrWalletService(Preferences preferences,
|
||||
CoreAccountService accountService,
|
||||
CoreMoneroConnectionsService connectionsService,
|
||||
WalletsSetup walletsSetup,
|
||||
XmrAddressEntryList xmrAddressEntryList,
|
||||
@Named(Config.WALLET_DIR) File walletDir,
|
||||
@Named(Config.WALLET_RPC_BIND_PORT) int rpcBindPort) {
|
||||
this.preferences = preferences;
|
||||
this.accountService = accountService;
|
||||
this.connectionsService = connectionsService;
|
||||
this.walletsSetup = walletsSetup;
|
||||
|
@ -212,6 +216,10 @@ public class XmrWalletService {
|
|||
public CoreMoneroConnectionsService getConnectionsService() {
|
||||
return connectionsService;
|
||||
}
|
||||
|
||||
public boolean isProxyApplied(boolean wasWalletSynced) {
|
||||
return preferences.isProxyApplied(wasWalletSynced);
|
||||
}
|
||||
|
||||
public String getWalletPassword() {
|
||||
return accountService.getPassword() == null ? MONERO_WALLET_RPC_DEFAULT_PASSWORD : accountService.getPassword();
|
||||
|
@ -231,13 +239,14 @@ public class XmrWalletService {
|
|||
null);
|
||||
}
|
||||
|
||||
public MoneroWalletRpc openWallet(String walletName) {
|
||||
public MoneroWalletRpc openWallet(String walletName, boolean applyProxyUri) {
|
||||
log.info("{}.openWallet({})", getClass().getSimpleName(), walletName);
|
||||
if (isShutDownStarted) throw new IllegalStateException("Cannot open wallet because shutting down");
|
||||
return openWalletRpc(new MoneroWalletConfig()
|
||||
.setPath(walletName)
|
||||
.setPassword(getWalletPassword()),
|
||||
null);
|
||||
null,
|
||||
applyProxyUri);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -670,7 +679,7 @@ public class XmrWalletService {
|
|||
log.info("Initializing main wallet with monerod=" + (daemon == null ? "null" : daemon.getRpcConnection().getUri()));
|
||||
MoneroWalletConfig walletConfig = new MoneroWalletConfig().setPath(MONERO_WALLET_NAME).setPassword(getWalletPassword());
|
||||
if (MoneroUtils.walletExists(xmrWalletFile.getPath())) {
|
||||
wallet = openWalletRpc(walletConfig, rpcBindPort);
|
||||
wallet = openWalletRpc(walletConfig, rpcBindPort, isProxyApplied(wasWalletSynced));
|
||||
} else if (connectionsService.getConnection() != null && Boolean.TRUE.equals(connectionsService.getConnection().isConnected())) {
|
||||
wallet = createWalletRpc(walletConfig, rpcBindPort);
|
||||
}
|
||||
|
@ -688,9 +697,13 @@ public class XmrWalletService {
|
|||
log.info("Syncing main wallet");
|
||||
long time = System.currentTimeMillis();
|
||||
wallet.sync(); // blocking
|
||||
wasWalletSynced = true;
|
||||
log.info("Done syncing main wallet in " + (System.currentTimeMillis() - time) + " ms");
|
||||
wallet.startSyncing(connectionsService.getRefreshPeriodMs());
|
||||
if (getMoneroNetworkType() != MoneroNetworkType.MAINNET) log.info("Monero wallet balance={}, unlocked balance={}", wallet.getBalance(0), wallet.getUnlockedBalance(0));
|
||||
|
||||
// reapply connection after wallet synced
|
||||
onConnectionChanged(connectionsService.getConnection());
|
||||
|
||||
// TODO: using this to signify both daemon and wallet synced, use separate sync handlers?
|
||||
connectionsService.doneDownload();
|
||||
|
@ -742,7 +755,7 @@ public class XmrWalletService {
|
|||
try {
|
||||
|
||||
// start monero-wallet-rpc instance
|
||||
walletRpc = startWalletRpcInstance(port);
|
||||
walletRpc = startWalletRpcInstance(port, isProxyApplied(false));
|
||||
walletRpc.getRpcConnection().setPrintStackTrace(PRINT_STACK_TRACE);
|
||||
|
||||
// prevent wallet rpc from syncing
|
||||
|
@ -762,20 +775,23 @@ public class XmrWalletService {
|
|||
}
|
||||
}
|
||||
|
||||
private MoneroWalletRpc openWalletRpc(MoneroWalletConfig config, Integer port) {
|
||||
private MoneroWalletRpc openWalletRpc(MoneroWalletConfig config, Integer port, boolean applyProxyUri) {
|
||||
MoneroWalletRpc walletRpc = null;
|
||||
try {
|
||||
|
||||
// start monero-wallet-rpc instance
|
||||
walletRpc = startWalletRpcInstance(port);
|
||||
walletRpc = startWalletRpcInstance(port, applyProxyUri);
|
||||
walletRpc.getRpcConnection().setPrintStackTrace(PRINT_STACK_TRACE);
|
||||
|
||||
// prevent wallet rpc from syncing
|
||||
walletRpc.stopSyncing();
|
||||
|
||||
// configure connection
|
||||
MoneroRpcConnection connection = new MoneroRpcConnection(connectionsService.getConnection());
|
||||
if (!applyProxyUri) connection.setProxyUri(null);
|
||||
|
||||
// open wallet
|
||||
log.info("Opening wallet " + config.getPath());
|
||||
walletRpc.openWallet(config.setServer(connectionsService.getConnection()));
|
||||
walletRpc.openWallet(config.setServer(connection));
|
||||
if (walletRpc.getDaemonConnection() != null) walletRpc.getDaemonConnection().setPrintStackTrace(PRINT_STACK_TRACE);
|
||||
log.info("Done opening wallet " + config.getPath());
|
||||
return walletRpc;
|
||||
|
@ -786,7 +802,7 @@ public class XmrWalletService {
|
|||
}
|
||||
}
|
||||
|
||||
private MoneroWalletRpc startWalletRpcInstance(Integer port) {
|
||||
private MoneroWalletRpc startWalletRpcInstance(Integer port, boolean applyProxyUri) {
|
||||
|
||||
// check if monero-wallet-rpc exists
|
||||
if (!new File(MONERO_WALLET_RPC_PATH).exists()) throw new Error("monero-wallet-rpc executable doesn't exist at path " + MONERO_WALLET_RPC_PATH
|
||||
|
@ -808,7 +824,7 @@ public class XmrWalletService {
|
|||
if (connection != null) {
|
||||
cmd.add("--daemon-address");
|
||||
cmd.add(connection.getUri());
|
||||
if (connection.getProxyUri() != null) {
|
||||
if (applyProxyUri && connection.getProxyUri() != null) { // TODO: only apply proxy if wallet is already synced, so we need a flag passed here
|
||||
cmd.add("--proxy");
|
||||
cmd.add(connection.getProxyUri());
|
||||
if (!connection.isOnion()) cmd.add("--daemon-ssl-allow-any-cert"); // necessary to use proxy with clearnet mmonerod
|
||||
|
@ -831,13 +847,12 @@ public class XmrWalletService {
|
|||
synchronized (walletLock) {
|
||||
if (isShutDownStarted) return;
|
||||
if (wallet != null && HavenoUtils.connectionConfigsEqual(connection, wallet.getDaemonConnection())) return;
|
||||
|
||||
log.info("Setting main wallet daemon connection: " + (connection == null ? null : connection.getUri()));
|
||||
String oldProxyUri = wallet == null || wallet.getDaemonConnection() == null ? null : wallet.getDaemonConnection().getProxyUri();
|
||||
String newProxyUri = connection == null ? null : connection.getProxyUri();
|
||||
log.info("Setting daemon connection for main wallet: uri={}, proxyUri={}", connection == null ? null : connection.getUri(), newProxyUri);
|
||||
if (wallet == null) maybeInitMainWallet(false);
|
||||
else if (wallet instanceof MoneroWalletRpc && !StringUtils.equals(oldProxyUri, newProxyUri)) {
|
||||
log.info("Restarting main wallet because proxy URI has changed");
|
||||
log.info("Restarting main wallet because proxy URI has changed, old={}, new={}", oldProxyUri, newProxyUri);
|
||||
closeMainWallet(true);
|
||||
maybeInitMainWallet(false);
|
||||
} else {
|
||||
|
|
|
@ -1254,7 +1254,7 @@ setting.preferences.prefCurrency=Preferred currency
|
|||
setting.preferences.displayTraditional=Display traditional currencies
|
||||
setting.preferences.noTraditional=There are no traditional currencies selected
|
||||
setting.preferences.cannotRemovePrefCurrency=You cannot remove your selected preferred display currency
|
||||
setting.preferences.displayCryptos=Display cryptose
|
||||
setting.preferences.displayCryptos=Display cryptos
|
||||
setting.preferences.noCryptos=There are no cryptos selected
|
||||
setting.preferences.addTraditional=Add traditional currency
|
||||
setting.preferences.addCrypto=Add cryptocurrency
|
||||
|
@ -1284,6 +1284,9 @@ settings.net.onionAddressLabel=My onion address
|
|||
settings.net.xmrNodesLabel=Use custom Monero nodes
|
||||
settings.net.moneroPeersLabel=Connected peers
|
||||
settings.net.useTorForXmrJLabel=Use Tor for Monero network
|
||||
settings.net.useTorForXmrAfterSyncRadio=After wallet is synchronized
|
||||
settings.net.useTorForXmrOffRadio=Never
|
||||
settings.net.useTorForXmrOnRadio=Always
|
||||
settings.net.moneroNodesLabel=Monero nodes to connect to
|
||||
settings.net.useProvidedNodesRadio=Use provided Monero nodes
|
||||
settings.net.usePublicNodesRadio=Use public Monero network
|
||||
|
|
|
@ -574,7 +574,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
|||
splashP2PNetworkBusyAnimation.stop();
|
||||
showTorNetworkSettingsButton.setVisible(true);
|
||||
showTorNetworkSettingsButton.setManaged(true);
|
||||
if (model.getUseTorForXMR().get()) {
|
||||
if (model.getUseTorForXmr().get().isUseTorForXmr()) {
|
||||
// If using tor for XMR, hide the XMR status since tor is not working
|
||||
xmrSyncIndicator.setVisible(false);
|
||||
xmrSplashInfo.setVisible(false);
|
||||
|
|
|
@ -47,6 +47,7 @@ import haveno.core.provider.price.PriceFeedService;
|
|||
import haveno.core.trade.TradeManager;
|
||||
import haveno.core.user.DontShowAgainLookup;
|
||||
import haveno.core.user.Preferences;
|
||||
import haveno.core.user.Preferences.UseTorForXmr;
|
||||
import haveno.core.user.User;
|
||||
import haveno.core.xmr.wallet.XmrWalletService;
|
||||
import haveno.desktop.Navigation;
|
||||
|
@ -628,8 +629,8 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener
|
|||
return havenoSetup.getXmrSplashSyncIconId();
|
||||
}
|
||||
|
||||
BooleanProperty getUseTorForXMR() {
|
||||
return havenoSetup.getUseTorForXMR();
|
||||
ObjectProperty<UseTorForXmr> getUseTorForXmr() {
|
||||
return havenoSetup.getUseTorForXmr();
|
||||
}
|
||||
|
||||
// P2P
|
||||
|
|
|
@ -73,7 +73,14 @@
|
|||
<AutoTooltipLabel fx:id="localhostXmrNodeInfoLabel" styleClass="small-text"/>
|
||||
</VBox>
|
||||
|
||||
<AutoTooltipCheckBox fx:id="useTorForXmrJCheckBox" GridPane.rowIndex="1"/>
|
||||
<VBox GridPane.rowIndex="1">
|
||||
<AutoTooltipLabel fx:id="useTorForXmrLabel" styleClass="small-text"/>
|
||||
<HBox spacing="10">
|
||||
<AutoTooltipRadioButton fx:id="useTorForXmrAfterSyncRadio"/>
|
||||
<AutoTooltipRadioButton fx:id="useTorForXmrOnRadio"/>
|
||||
<AutoTooltipRadioButton fx:id="useTorForXmrOffRadio"/>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
||||
<VBox GridPane.rowIndex="2">
|
||||
<AutoTooltipLabel fx:id="moneroNodesLabel" styleClass="small-text"/>
|
||||
|
|
|
@ -49,7 +49,6 @@ import javafx.collections.transformation.SortedList;
|
|||
import javafx.fxml.FXML;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.VPos;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.RadioButton;
|
||||
import javafx.scene.control.TableColumn;
|
||||
|
@ -75,7 +74,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
|
|||
@FXML
|
||||
TitledGroupBg p2pHeader, btcHeader;
|
||||
@FXML
|
||||
Label xmrNodesLabel, moneroNodesLabel, localhostXmrNodeInfoLabel;
|
||||
Label useTorForXmrLabel, xmrNodesLabel, moneroNodesLabel, localhostXmrNodeInfoLabel;
|
||||
@FXML
|
||||
InputTextField xmrNodesInputTextField;
|
||||
@FXML
|
||||
|
@ -83,7 +82,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
|
|||
@FXML
|
||||
Label p2PPeersLabel, moneroPeersLabel;
|
||||
@FXML
|
||||
CheckBox useTorForXmrJCheckBox;
|
||||
RadioButton useTorForXmrAfterSyncRadio, useTorForXmrOffRadio, useTorForXmrOnRadio;
|
||||
@FXML
|
||||
RadioButton useProvidedNodesRadio, useCustomNodesRadio, usePublicNodesRadio;
|
||||
@FXML
|
||||
|
@ -122,8 +121,11 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
|
|||
private Subscription moneroBlockHeightSubscription;
|
||||
private Subscription nodeAddressSubscription;
|
||||
private ChangeListener<Boolean> xmrNodesInputTextFieldFocusListener;
|
||||
private ToggleGroup useTorForXmrToggleGroup;
|
||||
private ToggleGroup moneroPeersToggleGroup;
|
||||
private Preferences.UseTorForXmr selectedUseTorForXmr;
|
||||
private XmrNodes.MoneroNodesOption selectedMoneroNodesOption;
|
||||
private ChangeListener<Toggle> useTorForXmrToggleGroupListener;
|
||||
private ChangeListener<Toggle> moneroPeersToggleGroupListener;
|
||||
private ChangeListener<Filter> filterPropertyListener;
|
||||
|
||||
|
@ -156,7 +158,10 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
|
|||
onionAddress.setPromptText(Res.get("settings.net.onionAddressLabel"));
|
||||
xmrNodesLabel.setText(Res.get("settings.net.xmrNodesLabel"));
|
||||
moneroPeersLabel.setText(Res.get("settings.net.moneroPeersLabel"));
|
||||
useTorForXmrJCheckBox.setText(Res.get("settings.net.useTorForXmrJLabel"));
|
||||
useTorForXmrLabel.setText(Res.get("settings.net.useTorForXmrJLabel"));
|
||||
useTorForXmrAfterSyncRadio.setText(Res.get("settings.net.useTorForXmrAfterSyncRadio"));
|
||||
useTorForXmrOffRadio.setText(Res.get("settings.net.useTorForXmrOffRadio"));
|
||||
useTorForXmrOnRadio.setText(Res.get("settings.net.useTorForXmrOnRadio"));
|
||||
moneroNodesLabel.setText(Res.get("settings.net.moneroNodesLabel"));
|
||||
moneroPeerAddressColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.onionAddressColumn")));
|
||||
moneroPeerAddressColumn.getStyleClass().add("first-column");
|
||||
|
@ -208,6 +213,31 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
|
|||
p2pPeersTableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData")));
|
||||
p2pPeersTableView.getSortOrder().add(creationDateColumn);
|
||||
creationDateColumn.setSortType(TableColumn.SortType.ASCENDING);
|
||||
|
||||
// use tor for xmr radio buttons
|
||||
|
||||
useTorForXmrToggleGroup = new ToggleGroup();
|
||||
useTorForXmrAfterSyncRadio.setToggleGroup(useTorForXmrToggleGroup);
|
||||
useTorForXmrOffRadio.setToggleGroup(useTorForXmrToggleGroup);
|
||||
useTorForXmrOnRadio.setToggleGroup(useTorForXmrToggleGroup);
|
||||
|
||||
useTorForXmrAfterSyncRadio.setUserData(Preferences.UseTorForXmr.AFTER_SYNC);
|
||||
useTorForXmrOffRadio.setUserData(Preferences.UseTorForXmr.OFF);
|
||||
useTorForXmrOnRadio.setUserData(Preferences.UseTorForXmr.ON);
|
||||
|
||||
selectedUseTorForXmr = Preferences.UseTorForXmr.values()[preferences.getUseTorForXmrOrdinal()];
|
||||
|
||||
selectUseTorForXmrToggle();
|
||||
onUseTorForXmrToggleSelected(false);
|
||||
|
||||
useTorForXmrToggleGroupListener = (observable, oldValue, newValue) -> {
|
||||
if (newValue != null) {
|
||||
selectedUseTorForXmr = (Preferences.UseTorForXmr) newValue.getUserData();
|
||||
onUseTorForXmrToggleSelected(true);
|
||||
}
|
||||
};
|
||||
|
||||
// monero nodes radio buttons
|
||||
|
||||
moneroPeersToggleGroup = new ToggleGroup();
|
||||
useProvidedNodesRadio.setToggleGroup(moneroPeersToggleGroup);
|
||||
|
@ -264,6 +294,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
|
|||
|
||||
@Override
|
||||
public void activate() {
|
||||
useTorForXmrToggleGroup.selectedToggleProperty().addListener(useTorForXmrToggleGroupListener);
|
||||
moneroPeersToggleGroup.selectedToggleProperty().addListener(moneroPeersToggleGroupListener);
|
||||
|
||||
if (filterManager.getFilter() != null)
|
||||
|
@ -271,22 +302,6 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
|
|||
|
||||
filterManager.filterProperty().addListener(filterPropertyListener);
|
||||
|
||||
useTorForXmrJCheckBox.setSelected(preferences.getUseTorForMonero());
|
||||
useTorForXmrJCheckBox.setOnAction(event -> {
|
||||
boolean selected = useTorForXmrJCheckBox.isSelected();
|
||||
if (selected != preferences.getUseTorForMonero()) {
|
||||
new Popup().information(Res.get("settings.net.needRestart"))
|
||||
.actionButtonText(Res.get("shared.applyAndShutDown"))
|
||||
.onAction(() -> {
|
||||
preferences.setUseTorForMonero(selected);
|
||||
UserThread.runAfter(HavenoApp.getShutDownHandler(), 500, TimeUnit.MILLISECONDS);
|
||||
})
|
||||
.closeButtonText(Res.get("shared.cancel"))
|
||||
.onClose(() -> useTorForXmrJCheckBox.setSelected(!selected))
|
||||
.show();
|
||||
}
|
||||
});
|
||||
|
||||
rescanOutputsButton.setOnAction(event -> GUIUtil.rescanOutputs(preferences));
|
||||
|
||||
moneroPeersSubscription = EasyBind.subscribe(connectionManager.peerConnectionsProperty(),
|
||||
|
@ -328,11 +343,10 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
|
|||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
useTorForXmrToggleGroup.selectedToggleProperty().removeListener(useTorForXmrToggleGroupListener);
|
||||
moneroPeersToggleGroup.selectedToggleProperty().removeListener(moneroPeersToggleGroupListener);
|
||||
filterManager.filterProperty().removeListener(filterPropertyListener);
|
||||
|
||||
useTorForXmrJCheckBox.setOnAction(null);
|
||||
|
||||
if (nodeAddressSubscription != null)
|
||||
nodeAddressSubscription.unsubscribe();
|
||||
|
||||
|
@ -360,6 +374,21 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
|
|||
return filterManager.getFilter() != null &&
|
||||
filterManager.getFilter().isPreventPublicXmrNetwork();
|
||||
}
|
||||
|
||||
private void selectUseTorForXmrToggle() {
|
||||
switch (selectedUseTorForXmr) {
|
||||
case OFF:
|
||||
useTorForXmrToggleGroup.selectToggle(useTorForXmrOffRadio);
|
||||
break;
|
||||
case ON:
|
||||
useTorForXmrToggleGroup.selectToggle(useTorForXmrOnRadio);
|
||||
break;
|
||||
default:
|
||||
case AFTER_SYNC:
|
||||
useTorForXmrToggleGroup.selectToggle(useTorForXmrAfterSyncRadio);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void selectMoneroPeersToggle() {
|
||||
switch (selectedMoneroNodesOption) {
|
||||
|
@ -383,10 +412,30 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
|
|||
.useShutDownButton()
|
||||
.show();
|
||||
}
|
||||
|
||||
private void onUseTorForXmrToggleSelected(boolean calledFromUser) {
|
||||
Preferences.UseTorForXmr currentUseTorForXmr = Preferences.UseTorForXmr.values()[preferences.getUseTorForXmrOrdinal()];
|
||||
if (currentUseTorForXmr != selectedUseTorForXmr) {
|
||||
if (calledFromUser) {
|
||||
new Popup().information(Res.get("settings.net.needRestart"))
|
||||
.actionButtonText(Res.get("shared.applyAndShutDown"))
|
||||
.onAction(() -> {
|
||||
preferences.setUseTorForXmrOrdinal(selectedUseTorForXmr.ordinal());
|
||||
UserThread.runAfter(HavenoApp.getShutDownHandler(), 500, TimeUnit.MILLISECONDS);
|
||||
})
|
||||
.closeButtonText(Res.get("shared.cancel"))
|
||||
.onClose(() -> {
|
||||
selectedUseTorForXmr = currentUseTorForXmr;
|
||||
selectUseTorForXmrToggle();
|
||||
})
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onMoneroPeersToggleSelected(boolean calledFromUser) {
|
||||
boolean localMoneroNodeShouldBeUsed = localMoneroNode.shouldBeUsed();
|
||||
useTorForXmrJCheckBox.setDisable(localMoneroNodeShouldBeUsed);
|
||||
useTorForXmrLabel.setDisable(localMoneroNodeShouldBeUsed);
|
||||
moneroNodesLabel.setDisable(localMoneroNodeShouldBeUsed);
|
||||
xmrNodesLabel.setDisable(localMoneroNodeShouldBeUsed);
|
||||
xmrNodesInputTextField.setDisable(localMoneroNodeShouldBeUsed);
|
||||
|
|
|
@ -1654,7 +1654,7 @@ message PreferencesPayload {
|
|||
bool auto_select_arbitrators = 8;
|
||||
map<string, bool> dont_show_again_map = 9;
|
||||
bool tac_accepted = 10;
|
||||
bool use_tor_for_monero = 11;
|
||||
int32 use_tor_for_xmr_ordinal = 11;
|
||||
bool show_own_offers_in_offer_book = 12;
|
||||
TradeCurrency preferred_trade_currency = 13;
|
||||
int64 withdrawal_tx_fee_in_vbytes = 14;
|
||||
|
|
Loading…
Reference in a new issue