mirror of
https://github.com/boldsuck/haveno.git
synced 2025-01-05 15:49:23 +00:00
Merge branch 'haveno-dex:master' into haveno-reto
This commit is contained in:
commit
cfbd7dc2e9
9 changed files with 144 additions and 66 deletions
|
@ -33,6 +33,7 @@ import haveno.core.xmr.model.XmrAddressEntry;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import monero.common.MoneroRpcConnection;
|
import monero.common.MoneroRpcConnection;
|
||||||
import monero.daemon.model.MoneroOutput;
|
import monero.daemon.model.MoneroOutput;
|
||||||
|
import monero.wallet.model.MoneroOutputWallet;
|
||||||
import monero.wallet.model.MoneroTxWallet;
|
import monero.wallet.model.MoneroTxWallet;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -62,7 +63,6 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
|
||||||
model.getXmrWalletService().getXmrConnectionService().verifyConnection();
|
model.getXmrWalletService().getXmrConnectionService().verifyConnection();
|
||||||
|
|
||||||
// create reserve tx
|
// create reserve tx
|
||||||
MoneroTxWallet reserveTx = null;
|
|
||||||
synchronized (HavenoUtils.xmrWalletService.getWalletLock()) {
|
synchronized (HavenoUtils.xmrWalletService.getWalletLock()) {
|
||||||
|
|
||||||
// reset protocol timeout
|
// reset protocol timeout
|
||||||
|
@ -79,6 +79,7 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
|
||||||
Integer preferredSubaddressIndex = fundingEntry == null ? null : fundingEntry.getSubaddressIndex();
|
Integer preferredSubaddressIndex = fundingEntry == null ? null : fundingEntry.getSubaddressIndex();
|
||||||
|
|
||||||
// attempt creating reserve tx
|
// attempt creating reserve tx
|
||||||
|
MoneroTxWallet reserveTx = null;
|
||||||
try {
|
try {
|
||||||
synchronized (HavenoUtils.getWalletFunctionLock()) {
|
synchronized (HavenoUtils.getWalletFunctionLock()) {
|
||||||
for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) {
|
for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) {
|
||||||
|
@ -121,6 +122,19 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
|
||||||
openOffer.setReserveTxHex(reserveTx.getFullHex());
|
openOffer.setReserveTxHex(reserveTx.getFullHex());
|
||||||
openOffer.setReserveTxKey(reserveTx.getKey());
|
openOffer.setReserveTxKey(reserveTx.getKey());
|
||||||
offer.getOfferPayload().setReserveTxKeyImages(reservedKeyImages);
|
offer.getOfferPayload().setReserveTxKeyImages(reservedKeyImages);
|
||||||
|
|
||||||
|
// reset offer funding address entry if unused
|
||||||
|
if (fundingEntry != null) {
|
||||||
|
List<MoneroOutputWallet> inputs = model.getXmrWalletService().getOutputs(reservedKeyImages);
|
||||||
|
boolean usesFundingEntry = false;
|
||||||
|
for (MoneroOutputWallet input : inputs) {
|
||||||
|
if (input.getAccountIndex() == 0 && input.getSubaddressIndex() == fundingEntry.getSubaddressIndex()) {
|
||||||
|
usesFundingEntry = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!usesFundingEntry) model.getXmrWalletService().swapAddressEntryToAvailable(offer.getId(), XmrAddressEntry.Context.OFFER_FUNDING);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
complete();
|
complete();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
|
|
@ -852,14 +852,6 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean requestSwitchToNextBestConnection(MoneroRpcConnection sourceConnection) {
|
|
||||||
if (xmrConnectionService.requestSwitchToNextBestConnection(sourceConnection)) {
|
|
||||||
onConnectionChanged(xmrConnectionService.getConnection()); // change connection on same thread
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isIdling() {
|
public boolean isIdling() {
|
||||||
return this instanceof ArbitratorTrade && isDepositsConfirmed() && walletExists() && pollNormalStartTimeMs == null; // arbitrator idles trade after deposits confirm unless overriden
|
return this instanceof ArbitratorTrade && isDepositsConfirmed() && walletExists() && pollNormalStartTimeMs == null; // arbitrator idles trade after deposits confirm unless overriden
|
||||||
}
|
}
|
||||||
|
@ -909,6 +901,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void requestSaveWallet() {
|
public void requestSaveWallet() {
|
||||||
|
|
||||||
// save wallet off main thread
|
// save wallet off main thread
|
||||||
|
@ -919,6 +912,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
||||||
}, getId());
|
}, getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void saveWallet() {
|
public void saveWallet() {
|
||||||
synchronized (walletLock) {
|
synchronized (walletLock) {
|
||||||
if (!walletExists()) {
|
if (!walletExists()) {
|
||||||
|
@ -2386,7 +2380,8 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
||||||
return tradeVolumeProperty;
|
return tradeVolumeProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onConnectionChanged(MoneroRpcConnection connection) {
|
@Override
|
||||||
|
protected void onConnectionChanged(MoneroRpcConnection connection) {
|
||||||
synchronized (walletLock) {
|
synchronized (walletLock) {
|
||||||
|
|
||||||
// use current connection
|
// use current connection
|
||||||
|
@ -2682,7 +2677,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model {
|
||||||
pollInProgress = false;
|
pollInProgress = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requestSaveWallet();
|
saveWalletWithDelay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import javafx.beans.property.LongProperty;
|
||||||
import javafx.beans.property.SimpleLongProperty;
|
import javafx.beans.property.SimpleLongProperty;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import monero.common.MoneroRpcConnection;
|
||||||
import monero.common.TaskLooper;
|
import monero.common.TaskLooper;
|
||||||
import monero.daemon.model.MoneroTx;
|
import monero.daemon.model.MoneroTx;
|
||||||
import monero.wallet.MoneroWallet;
|
import monero.wallet.MoneroWallet;
|
||||||
|
@ -24,16 +25,18 @@ import monero.wallet.MoneroWalletFull;
|
||||||
import monero.wallet.model.MoneroWalletListener;
|
import monero.wallet.model.MoneroWalletListener;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class XmrWalletBase {
|
public abstract class XmrWalletBase {
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
public static final int SYNC_PROGRESS_TIMEOUT_SECONDS = 120;
|
public static final int SYNC_PROGRESS_TIMEOUT_SECONDS = 120;
|
||||||
public static final int DIRECT_SYNC_WITHIN_BLOCKS = 100;
|
public static final int DIRECT_SYNC_WITHIN_BLOCKS = 100;
|
||||||
|
public static final int SAVE_WALLET_DELAY_SECONDS = 300;
|
||||||
|
|
||||||
// inherited
|
// inherited
|
||||||
protected MoneroWallet wallet;
|
protected MoneroWallet wallet;
|
||||||
@Getter
|
@Getter
|
||||||
protected final Object walletLock = new Object();
|
protected final Object walletLock = new Object();
|
||||||
|
protected Timer saveWalletDelayTimer;
|
||||||
@Getter
|
@Getter
|
||||||
protected XmrConnectionService xmrConnectionService;
|
protected XmrConnectionService xmrConnectionService;
|
||||||
protected boolean wasWalletSynced;
|
protected boolean wasWalletSynced;
|
||||||
|
@ -137,6 +140,34 @@ public class XmrWalletBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean requestSwitchToNextBestConnection(MoneroRpcConnection sourceConnection) {
|
||||||
|
if (xmrConnectionService.requestSwitchToNextBestConnection(sourceConnection)) {
|
||||||
|
onConnectionChanged(xmrConnectionService.getConnection()); // change connection on same thread
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveWalletWithDelay() {
|
||||||
|
// delay writing to disk to avoid frequent write operations
|
||||||
|
if (saveWalletDelayTimer == null) {
|
||||||
|
saveWalletDelayTimer = UserThread.runAfter(() -> {
|
||||||
|
requestSaveWallet();
|
||||||
|
UserThread.execute(() -> saveWalletDelayTimer = null);
|
||||||
|
}, SAVE_WALLET_DELAY_SECONDS, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------- ABSTRACT -----------------------------
|
||||||
|
|
||||||
|
public abstract void saveWallet();
|
||||||
|
|
||||||
|
public abstract void requestSaveWallet();
|
||||||
|
|
||||||
|
protected abstract void onConnectionChanged(MoneroRpcConnection connection);
|
||||||
|
|
||||||
|
// ------------------------------ PRIVATE HELPERS -------------------------
|
||||||
|
|
||||||
private void updateSyncProgress(long height, long targetHeight) {
|
private void updateSyncProgress(long height, long targetHeight) {
|
||||||
resetSyncProgressTimeout();
|
resetSyncProgressTimeout();
|
||||||
UserThread.execute(() -> {
|
UserThread.execute(() -> {
|
||||||
|
|
|
@ -245,16 +245,20 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
return user.getWalletCreationDate();
|
return user.getWalletCreationDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveMainWallet() {
|
@Override
|
||||||
saveMainWallet(!(Utilities.isWindows() && wallet != null));
|
public void saveWallet() {
|
||||||
|
saveWallet(!(Utilities.isWindows() && wallet != null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveMainWallet(boolean backup) {
|
public void saveWallet(boolean backup) {
|
||||||
saveWallet(getWallet(), backup);
|
synchronized (walletLock) {
|
||||||
|
saveWallet(getWallet(), backup);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void requestSaveMainWallet() {
|
@Override
|
||||||
ThreadUtils.submitToPool(() -> saveMainWallet()); // save wallet off main thread
|
public void requestSaveWallet() {
|
||||||
|
ThreadUtils.submitToPool(() -> saveWallet()); // save wallet off main thread
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isWalletAvailable() {
|
public boolean isWalletAvailable() {
|
||||||
|
@ -376,8 +380,8 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveWallet(MoneroWallet wallet, boolean backup) {
|
public void saveWallet(MoneroWallet wallet, boolean backup) {
|
||||||
wallet.save();
|
|
||||||
if (backup) backupWallet(getWalletName(wallet.getPath()));
|
if (backup) backupWallet(getWalletName(wallet.getPath()));
|
||||||
|
wallet.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closeWallet(MoneroWallet wallet, boolean save) {
|
public void closeWallet(MoneroWallet wallet, boolean save) {
|
||||||
|
@ -385,8 +389,8 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
MoneroError err = null;
|
MoneroError err = null;
|
||||||
String path = wallet.getPath();
|
String path = wallet.getPath();
|
||||||
try {
|
try {
|
||||||
wallet.close(save);
|
if (save) saveWallet(wallet, true);
|
||||||
if (save) backupWallet(getWalletName(path));
|
wallet.close();
|
||||||
} catch (MoneroError e) {
|
} catch (MoneroError e) {
|
||||||
err = e;
|
err = e;
|
||||||
}
|
}
|
||||||
|
@ -443,7 +447,7 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
if (Boolean.TRUE.equals(txConfig.getRelay())) {
|
if (Boolean.TRUE.equals(txConfig.getRelay())) {
|
||||||
cachedTxs.addFirst(tx);
|
cachedTxs.addFirst(tx);
|
||||||
cacheWalletInfo();
|
cacheWalletInfo();
|
||||||
requestSaveMainWallet();
|
requestSaveWallet();
|
||||||
}
|
}
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
|
@ -453,7 +457,7 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
public String relayTx(String metadata) {
|
public String relayTx(String metadata) {
|
||||||
synchronized (walletLock) {
|
synchronized (walletLock) {
|
||||||
String txId = wallet.relayTx(metadata);
|
String txId = wallet.relayTx(metadata);
|
||||||
requestSaveMainWallet();
|
requestSaveWallet();
|
||||||
return txId;
|
return txId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -552,7 +556,7 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
// freeze outputs
|
// freeze outputs
|
||||||
for (String keyImage : unfrozenKeyImages) wallet.freezeOutput(keyImage);
|
for (String keyImage : unfrozenKeyImages) wallet.freezeOutput(keyImage);
|
||||||
cacheWalletInfo();
|
cacheWalletInfo();
|
||||||
requestSaveMainWallet();
|
requestSaveWallet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,19 +578,10 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
// thaw outputs
|
// thaw outputs
|
||||||
for (String keyImage : frozenKeyImages) wallet.thawOutput(keyImage);
|
for (String keyImage : frozenKeyImages) wallet.thawOutput(keyImage);
|
||||||
cacheWalletInfo();
|
cacheWalletInfo();
|
||||||
requestSaveMainWallet();
|
requestSaveWallet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigInteger getOutputsAmount(Collection<String> keyImages) {
|
|
||||||
BigInteger sum = BigInteger.ZERO;
|
|
||||||
for (String keyImage : keyImages) {
|
|
||||||
List<MoneroOutputWallet> outputs = getOutputs(new MoneroOutputQuery().setIsSpent(false).setKeyImage(new MoneroKeyImage(keyImage)));
|
|
||||||
if (!outputs.isEmpty()) sum = sum.add(outputs.get(0).getAmount());
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Integer> getSubaddressesWithExactInput(BigInteger amount) {
|
private List<Integer> getSubaddressesWithExactInput(BigInteger amount) {
|
||||||
|
|
||||||
// fetch unspent, unfrozen, unlocked outputs
|
// fetch unspent, unfrozen, unlocked outputs
|
||||||
|
@ -1125,6 +1120,15 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
return subaddress == null ? BigInteger.ZERO : subaddress.getBalance();
|
return subaddress == null ? BigInteger.ZERO : subaddress.getBalance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BigInteger getBalanceForSubaddress(int subaddressIndex, boolean includeFrozen) {
|
||||||
|
return getBalanceForSubaddress(subaddressIndex).add(includeFrozen ? getFrozenBalanceForSubaddress(subaddressIndex) : BigInteger.ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getFrozenBalanceForSubaddress(int subaddressIndex) {
|
||||||
|
List<MoneroOutputWallet> outputs = getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false).setAccountIndex(0).setSubaddressIndex(subaddressIndex));
|
||||||
|
return outputs.stream().map(output -> output.getAmount()).reduce(BigInteger.ZERO, BigInteger::add);
|
||||||
|
}
|
||||||
|
|
||||||
public BigInteger getAvailableBalanceForSubaddress(int subaddressIndex) {
|
public BigInteger getAvailableBalanceForSubaddress(int subaddressIndex) {
|
||||||
MoneroSubaddress subaddress = getSubaddress(subaddressIndex);
|
MoneroSubaddress subaddress = getSubaddress(subaddressIndex);
|
||||||
return subaddress == null ? BigInteger.ZERO : subaddress.getUnlockedBalance();
|
return subaddress == null ? BigInteger.ZERO : subaddress.getUnlockedBalance();
|
||||||
|
@ -1250,6 +1254,19 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
return filteredOutputs;
|
return filteredOutputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<MoneroOutputWallet> getOutputs(Collection<String> keyImages) {
|
||||||
|
List<MoneroOutputWallet> outputs = new ArrayList<MoneroOutputWallet>();
|
||||||
|
for (String keyImage : keyImages) {
|
||||||
|
List<MoneroOutputWallet> outputList = getOutputs(new MoneroOutputQuery().setIsSpent(false).setKeyImage(new MoneroKeyImage(keyImage)));
|
||||||
|
if (!outputList.isEmpty()) outputs.add(outputList.get(0));
|
||||||
|
}
|
||||||
|
return outputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getOutputsAmount(Collection<String> keyImages) {
|
||||||
|
return getOutputs(keyImages).stream().map(output -> output.getAmount()).reduce(BigInteger.ZERO, BigInteger::add);
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Util
|
// Util
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1321,7 +1338,7 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
maybeInitMainWallet(sync, MAX_SYNC_ATTEMPTS);
|
maybeInitMainWallet(sync, MAX_SYNC_ATTEMPTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeInitMainWallet(boolean sync, int numAttempts) {
|
private void maybeInitMainWallet(boolean sync, int numSyncAttempts) {
|
||||||
ThreadUtils.execute(() -> {
|
ThreadUtils.execute(() -> {
|
||||||
try {
|
try {
|
||||||
doMaybeInitMainWallet(sync, MAX_SYNC_ATTEMPTS);
|
doMaybeInitMainWallet(sync, MAX_SYNC_ATTEMPTS);
|
||||||
|
@ -1333,7 +1350,7 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
}, THREAD_ID);
|
}, THREAD_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doMaybeInitMainWallet(boolean sync, int numAttempts) {
|
private void doMaybeInitMainWallet(boolean sync, int numSyncAttempts) {
|
||||||
synchronized (walletLock) {
|
synchronized (walletLock) {
|
||||||
if (isShutDownStarted) return;
|
if (isShutDownStarted) return;
|
||||||
|
|
||||||
|
@ -1361,7 +1378,7 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
|
|
||||||
// sync main wallet if applicable
|
// sync main wallet if applicable
|
||||||
// TODO: error handling and re-initialization is jenky, refactor
|
// TODO: error handling and re-initialization is jenky, refactor
|
||||||
if (sync && numAttempts > 0) {
|
if (sync && numSyncAttempts > 0) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// switch connection if disconnected
|
// switch connection if disconnected
|
||||||
|
@ -1380,7 +1397,7 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
log.warn("Error syncing wallet with progress on startup: " + e.getMessage());
|
log.warn("Error syncing wallet with progress on startup: " + e.getMessage());
|
||||||
forceCloseMainWallet();
|
forceCloseMainWallet();
|
||||||
requestSwitchToNextBestConnection(sourceConnection);
|
requestSwitchToNextBestConnection(sourceConnection);
|
||||||
maybeInitMainWallet(true, numAttempts - 1); // re-initialize wallet and sync again
|
maybeInitMainWallet(true, numSyncAttempts - 1); // re-initialize wallet and sync again
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.info("Done syncing main wallet in " + (System.currentTimeMillis() - time) + " ms");
|
log.info("Done syncing main wallet in " + (System.currentTimeMillis() - time) + " ms");
|
||||||
|
@ -1411,14 +1428,14 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
HavenoUtils.havenoSetup.getWalletInitialized().set(true);
|
HavenoUtils.havenoSetup.getWalletInitialized().set(true);
|
||||||
|
|
||||||
// save but skip backup on initialization
|
// save but skip backup on initialization
|
||||||
saveMainWallet(false);
|
saveWallet(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (isClosingWallet || isShutDownStarted || HavenoUtils.havenoSetup.getWalletInitialized().get()) return; // ignore if wallet closing, shut down started, or app already initialized
|
if (isClosingWallet || isShutDownStarted || HavenoUtils.havenoSetup.getWalletInitialized().get()) return; // ignore if wallet closing, shut down started, or app already initialized
|
||||||
log.warn("Error initially syncing main wallet: {}", e.getMessage());
|
log.warn("Error initially syncing main wallet: {}", e.getMessage());
|
||||||
if (numAttempts <= 1) {
|
if (numSyncAttempts <= 1) {
|
||||||
log.warn("Failed to sync main wallet. Opening app without syncing", numAttempts);
|
log.warn("Failed to sync main wallet. Opening app without syncing", numSyncAttempts);
|
||||||
HavenoUtils.havenoSetup.getWalletInitialized().set(true);
|
HavenoUtils.havenoSetup.getWalletInitialized().set(true);
|
||||||
saveMainWallet(false);
|
saveWallet(false);
|
||||||
|
|
||||||
// reschedule to init main wallet
|
// reschedule to init main wallet
|
||||||
UserThread.runAfter(() -> {
|
UserThread.runAfter(() -> {
|
||||||
|
@ -1427,7 +1444,7 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
} else {
|
} else {
|
||||||
log.warn("Trying again in {} seconds", xmrConnectionService.getRefreshPeriodMs() / 1000);
|
log.warn("Trying again in {} seconds", xmrConnectionService.getRefreshPeriodMs() / 1000);
|
||||||
UserThread.runAfter(() -> {
|
UserThread.runAfter(() -> {
|
||||||
maybeInitMainWallet(true, numAttempts - 1);
|
maybeInitMainWallet(true, numSyncAttempts - 1);
|
||||||
}, xmrConnectionService.getRefreshPeriodMs() / 1000);
|
}, xmrConnectionService.getRefreshPeriodMs() / 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1741,7 +1758,8 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
return MONERO_WALLET_RPC_MANAGER.startInstance(cmd);
|
return MONERO_WALLET_RPC_MANAGER.startInstance(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onConnectionChanged(MoneroRpcConnection connection) {
|
@Override
|
||||||
|
protected void onConnectionChanged(MoneroRpcConnection connection) {
|
||||||
synchronized (walletLock) {
|
synchronized (walletLock) {
|
||||||
|
|
||||||
// use current connection
|
// use current connection
|
||||||
|
@ -1795,7 +1813,7 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
tasks.add(() -> {
|
tasks.add(() -> {
|
||||||
try {
|
try {
|
||||||
wallet.changePassword(oldPassword, newPassword);
|
wallet.changePassword(oldPassword, newPassword);
|
||||||
saveMainWallet();
|
saveWallet();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Error changing main wallet password: " + e.getMessage() + "\n", e);
|
log.warn("Error changing main wallet password: " + e.getMessage() + "\n", e);
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -1845,13 +1863,13 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
log.warn("Force restarting main wallet");
|
log.warn("Force restarting main wallet");
|
||||||
if (isClosingWallet) return;
|
if (isClosingWallet) return;
|
||||||
forceCloseMainWallet();
|
forceCloseMainWallet();
|
||||||
maybeInitMainWallet(true);
|
doMaybeInitMainWallet(true, MAX_SYNC_ATTEMPTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleWalletError(Exception e, MoneroRpcConnection sourceConnection) {
|
public void handleWalletError(Exception e, MoneroRpcConnection sourceConnection) {
|
||||||
if (HavenoUtils.isUnresponsive(e)) forceCloseMainWallet(); // wallet can be stuck a while
|
if (HavenoUtils.isUnresponsive(e)) forceCloseMainWallet(); // wallet can be stuck a while
|
||||||
if (xmrConnectionService.isConnected()) requestSwitchToNextBestConnection(sourceConnection);
|
requestSwitchToNextBestConnection(sourceConnection);
|
||||||
getWallet(); // re-open wallet
|
if (wallet == null) doMaybeInitMainWallet(true, MAX_SYNC_ATTEMPTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startPolling() {
|
private void startPolling() {
|
||||||
|
@ -1988,7 +2006,7 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
if (wallet != null && !isShutDownStarted) {
|
if (wallet != null && !isShutDownStarted) {
|
||||||
try {
|
try {
|
||||||
cacheWalletInfo();
|
cacheWalletInfo();
|
||||||
requestSaveMainWallet();
|
saveWalletWithDelay();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Error caching wallet info: " + e.getMessage() + "\n", e);
|
log.warn("Error caching wallet info: " + e.getMessage() + "\n", e);
|
||||||
}
|
}
|
||||||
|
@ -2020,10 +2038,6 @@ public class XmrWalletService extends XmrWalletBase {
|
||||||
return requestSwitchToNextBestConnection(null);
|
return requestSwitchToNextBestConnection(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean requestSwitchToNextBestConnection(MoneroRpcConnection sourceConnection) {
|
|
||||||
return xmrConnectionService.requestSwitchToNextBestConnection(sourceConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onNewBlock(long height) {
|
private void onNewBlock(long height) {
|
||||||
UserThread.execute(() -> {
|
UserThread.execute(() -> {
|
||||||
walletHeight.set(height);
|
walletHeight.set(height);
|
||||||
|
|
|
@ -29,6 +29,7 @@ import haveno.desktop.setup.DesktopPersistedDataHost;
|
||||||
import haveno.desktop.util.ImageUtil;
|
import haveno.desktop.util.ImageUtil;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.ButtonBar;
|
import javafx.scene.control.ButtonBar;
|
||||||
import javafx.scene.control.ButtonType;
|
import javafx.scene.control.ButtonType;
|
||||||
import javafx.scene.control.Dialog;
|
import javafx.scene.control.Dialog;
|
||||||
|
@ -210,9 +211,13 @@ public class HavenoAppMain extends HavenoExecutable {
|
||||||
Label errorMessageField = new Label(errorMessage);
|
Label errorMessageField = new Label(errorMessage);
|
||||||
errorMessageField.setTextFill(Color.color(1, 0, 0));
|
errorMessageField.setTextFill(Color.color(1, 0, 0));
|
||||||
|
|
||||||
|
// Create the version field
|
||||||
|
Label versionField = new Label("v" + Version.VERSION);
|
||||||
|
|
||||||
// Set the dialog content
|
// Set the dialog content
|
||||||
VBox vbox = new VBox(10);
|
VBox vbox = new VBox(10);
|
||||||
vbox.getChildren().addAll(new ImageView(ImageUtil.getImageByPath("logo_splash.png")), passwordField, errorMessageField);
|
vbox.getChildren().addAll(new ImageView(ImageUtil.getImageByPath("logo_splash.png")), versionField, passwordField, errorMessageField);
|
||||||
|
vbox.setAlignment(Pos.TOP_CENTER);
|
||||||
getDialogPane().setContent(vbox);
|
getDialogPane().setContent(vbox);
|
||||||
|
|
||||||
// Add OK and Cancel buttons
|
// Add OK and Cancel buttons
|
||||||
|
|
|
@ -20,6 +20,7 @@ package haveno.desktop.main;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.jfoenix.controls.JFXBadge;
|
import com.jfoenix.controls.JFXBadge;
|
||||||
import com.jfoenix.controls.JFXComboBox;
|
import com.jfoenix.controls.JFXComboBox;
|
||||||
|
import haveno.common.app.Version;
|
||||||
import haveno.common.HavenoException;
|
import haveno.common.HavenoException;
|
||||||
import haveno.common.Timer;
|
import haveno.common.Timer;
|
||||||
import haveno.common.UserThread;
|
import haveno.common.UserThread;
|
||||||
|
@ -510,6 +511,8 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||||
ImageView logo = new ImageView();
|
ImageView logo = new ImageView();
|
||||||
logo.setId(Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_MAINNET ? "image-splash-logo" : "image-splash-testnet-logo");
|
logo.setId(Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_MAINNET ? "image-splash-logo" : "image-splash-testnet-logo");
|
||||||
|
|
||||||
|
Label versionLabel = new Label("v" + Version.VERSION);
|
||||||
|
|
||||||
// createBitcoinInfoBox
|
// createBitcoinInfoBox
|
||||||
xmrSplashInfo = new AutoTooltipLabel();
|
xmrSplashInfo = new AutoTooltipLabel();
|
||||||
xmrSplashInfo.textProperty().bind(model.getXmrInfo());
|
xmrSplashInfo.textProperty().bind(model.getXmrInfo());
|
||||||
|
@ -621,7 +624,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
|
||||||
splashP2PNetworkBox.setPrefHeight(40);
|
splashP2PNetworkBox.setPrefHeight(40);
|
||||||
splashP2PNetworkBox.getChildren().addAll(splashP2PNetworkLabel, splashP2PNetworkBusyAnimation, splashP2PNetworkIcon, showTorNetworkSettingsButton);
|
splashP2PNetworkBox.getChildren().addAll(splashP2PNetworkLabel, splashP2PNetworkBusyAnimation, splashP2PNetworkIcon, showTorNetworkSettingsButton);
|
||||||
|
|
||||||
vBox.getChildren().addAll(logo, blockchainSyncBox, xmrSyncIndicator, splashP2PNetworkBox);
|
vBox.getChildren().addAll(logo, versionLabel, blockchainSyncBox, xmrSyncIndicator, splashP2PNetworkBox);
|
||||||
return vBox;
|
return vBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ class DepositListItem {
|
||||||
this.xmrWalletService = xmrWalletService;
|
this.xmrWalletService = xmrWalletService;
|
||||||
this.addressEntry = addressEntry;
|
this.addressEntry = addressEntry;
|
||||||
|
|
||||||
balanceAsBI = xmrWalletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex());
|
balanceAsBI = xmrWalletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex(), true);
|
||||||
balance.set(HavenoUtils.formatXmr(balanceAsBI));
|
balance.set(HavenoUtils.formatXmr(balanceAsBI));
|
||||||
|
|
||||||
updateUsage(addressEntry.getSubaddressIndex());
|
updateUsage(addressEntry.getSubaddressIndex());
|
||||||
|
|
|
@ -508,12 +508,14 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateP2PTable() {
|
private void updateP2PTable() {
|
||||||
if (connectionService.isShutDownStarted()) return; // ignore if shutting down
|
UserThread.execute(() -> {
|
||||||
p2pPeersTableView.getItems().forEach(P2pNetworkListItem::cleanup);
|
if (connectionService.isShutDownStarted()) return; // ignore if shutting down
|
||||||
p2pNetworkListItems.clear();
|
p2pPeersTableView.getItems().forEach(P2pNetworkListItem::cleanup);
|
||||||
p2pNetworkListItems.setAll(p2PService.getNetworkNode().getAllConnections().stream()
|
p2pNetworkListItems.clear();
|
||||||
.map(connection -> new P2pNetworkListItem(connection, clockWatcher))
|
p2pNetworkListItems.setAll(p2PService.getNetworkNode().getAllConnections().stream()
|
||||||
.collect(Collectors.toList()));
|
.map(connection -> new P2pNetworkListItem(connection, clockWatcher))
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateMoneroConnectionsTable() {
|
private void updateMoneroConnectionsTable() {
|
||||||
|
@ -521,7 +523,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
|
||||||
if (connectionService.isShutDownStarted()) return; // ignore if shutting down
|
if (connectionService.isShutDownStarted()) return; // ignore if shutting down
|
||||||
moneroNetworkListItems.clear();
|
moneroNetworkListItems.clear();
|
||||||
moneroNetworkListItems.setAll(connectionService.getConnections().stream()
|
moneroNetworkListItems.setAll(connectionService.getConnections().stream()
|
||||||
.map(connection -> new MoneroNetworkListItem(connection, Boolean.TRUE.equals(connection.isConnected()) && connection == connectionService.getConnection()))
|
.map(connection -> new MoneroNetworkListItem(connection, connection == connectionService.getConnection() && Boolean.TRUE.equals(connectionService.isConnected())))
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
updateChainHeightTextField(connectionService.chainHeightProperty().get());
|
updateChainHeightTextField(connectionService.chainHeightProperty().get());
|
||||||
});
|
});
|
||||||
|
|
|
@ -178,6 +178,8 @@ public class Connection implements HasCapabilities, Runnable, MessageListener {
|
||||||
private static int numThrottledInvalidRequestReports = 0;
|
private static int numThrottledInvalidRequestReports = 0;
|
||||||
private static long lastLoggedWarningTs = 0;
|
private static long lastLoggedWarningTs = 0;
|
||||||
private static int numThrottledWarnings = 0;
|
private static int numThrottledWarnings = 0;
|
||||||
|
private static long lastLoggedInfoTs = 0;
|
||||||
|
private static int numThrottledInfos = 0;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor
|
// Constructor
|
||||||
|
@ -676,7 +678,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener {
|
||||||
throttleWarn("SocketException (expected if connection lost). closeConnectionReason=" + closeConnectionReason + "; connection=" + this);
|
throttleWarn("SocketException (expected if connection lost). closeConnectionReason=" + closeConnectionReason + "; connection=" + this);
|
||||||
} else if (e instanceof SocketTimeoutException || e instanceof TimeoutException) {
|
} else if (e instanceof SocketTimeoutException || e instanceof TimeoutException) {
|
||||||
closeConnectionReason = CloseConnectionReason.SOCKET_TIMEOUT;
|
closeConnectionReason = CloseConnectionReason.SOCKET_TIMEOUT;
|
||||||
throttleWarn("Shut down caused by exception " + e.getMessage() + " on connection=" + this);
|
throttleInfo("Shut down caused by exception " + e.getMessage() + " on connection=" + this);
|
||||||
} else if (e instanceof EOFException) {
|
} else if (e instanceof EOFException) {
|
||||||
closeConnectionReason = CloseConnectionReason.TERMINATED;
|
closeConnectionReason = CloseConnectionReason.TERMINATED;
|
||||||
throttleWarn("Shut down caused by exception " + e.getMessage() + " on connection=" + this);
|
throttleWarn("Shut down caused by exception " + e.getMessage() + " on connection=" + this);
|
||||||
|
@ -937,8 +939,8 @@ public class Connection implements HasCapabilities, Runnable, MessageListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void throttleWarn(String msg) {
|
private synchronized void throttleWarn(String msg) {
|
||||||
boolean logWarning = System.currentTimeMillis() - lastLoggedWarningTs > LOG_THROTTLE_INTERVAL_MS;
|
boolean doLog = System.currentTimeMillis() - lastLoggedWarningTs > LOG_THROTTLE_INTERVAL_MS;
|
||||||
if (logWarning) {
|
if (doLog) {
|
||||||
log.warn(msg);
|
log.warn(msg);
|
||||||
if (numThrottledWarnings > 0) log.warn("{} warnings were throttled since the last log entry", numThrottledWarnings);
|
if (numThrottledWarnings > 0) log.warn("{} warnings were throttled since the last log entry", numThrottledWarnings);
|
||||||
numThrottledWarnings = 0;
|
numThrottledWarnings = 0;
|
||||||
|
@ -947,4 +949,16 @@ public class Connection implements HasCapabilities, Runnable, MessageListener {
|
||||||
numThrottledWarnings++;
|
numThrottledWarnings++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized void throttleInfo(String msg) {
|
||||||
|
boolean doLog = System.currentTimeMillis() - lastLoggedInfoTs > LOG_THROTTLE_INTERVAL_MS;
|
||||||
|
if (doLog) {
|
||||||
|
log.info(msg);
|
||||||
|
if (numThrottledInfos > 0) log.info("{} info logs were throttled since the last log entry", numThrottledInfos);
|
||||||
|
numThrottledInfos = 0;
|
||||||
|
lastLoggedInfoTs = System.currentTimeMillis();
|
||||||
|
} else {
|
||||||
|
numThrottledInfos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue