diff --git a/README.md b/README.md index 483c7e7a..465e04f9 100644 --- a/README.md +++ b/README.md @@ -71,14 +71,16 @@ To bring Haveno to life, we need resources. If you have the possibility, please ### Monero -`42sjokkT9FmiWPqVzrWPFE5NCJXwt96bkBozHf4vgLR9hXyJDqKHEHKVscAARuD7in5wV1meEcSTJTanCTDzidTe2cFXS1F` - - +

+ Donate Monero
+ 42sjokkT9FmiWPqVzrWPFE5NCJXwt96bkBozHf4vgLR9hXyJDqKHEHKVscAARuD7in5wV1meEcSTJTanCTDzidTe2cFXS1F +

If you are using a wallet that supports OpenAlias (like the 'official' CLI and GUI wallets), you can simply put `fund@haveno.exchange` as the "receiver" address. ### Bitcoin -`1AKq3CE1yBAnxGmHXbNFfNYStcByNDc5gQ` - - +

+ Donate Bitcoin
+ 1AKq3CE1yBAnxGmHXbNFfNYStcByNDc5gQ +

diff --git a/build.gradle b/build.gradle index 06020557..83d42efb 100644 --- a/build.gradle +++ b/build.gradle @@ -317,6 +317,8 @@ configure(project(':common')) { exclude(module: 'animal-sniffer-annotations') } + // override transitive dependency and use latest version from bisq + implementation(group: 'com.github.bisq-network', name: 'jtorctl') { version { strictly "[b2a172f44edcd8deaa5ed75d936dcbb007f0d774]" } } implementation "org.openjfx:javafx-base:$javafxVersion:$os" implementation "org.openjfx:javafx-graphics:$javafxVersion:$os" } @@ -607,7 +609,7 @@ configure(project(':desktop')) { apply plugin: 'com.github.johnrengelman.shadow' apply from: 'package/package.gradle' - version = '1.0.10-SNAPSHOT' + version = '1.0.11-SNAPSHOT' jar.manifest.attributes( "Implementation-Title": project.name, diff --git a/common/src/main/java/haveno/common/app/Version.java b/common/src/main/java/haveno/common/app/Version.java index c8ab2551..e224c13d 100644 --- a/common/src/main/java/haveno/common/app/Version.java +++ b/common/src/main/java/haveno/common/app/Version.java @@ -28,7 +28,7 @@ import static com.google.common.base.Preconditions.checkArgument; public class Version { // The application versions // We use semantic versioning with major, minor and patch - public static final String VERSION = "1.0.10"; + public static final String VERSION = "1.0.11"; /** * Holds a list of the tagged resource files for optimizing the getData requests. diff --git a/common/src/main/java/haveno/common/file/FileUtil.java b/common/src/main/java/haveno/common/file/FileUtil.java index 60ac2c3a..449faea6 100644 --- a/common/src/main/java/haveno/common/file/FileUtil.java +++ b/common/src/main/java/haveno/common/file/FileUtil.java @@ -40,10 +40,13 @@ import java.util.Scanner; @Slf4j public class FileUtil { + + private static final String BACKUP_DIR = "backup"; + public static void rollingBackup(File dir, String fileName, int numMaxBackupFiles) { if (numMaxBackupFiles <= 0) return; if (dir.exists()) { - File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString()); + File backupDir = new File(Paths.get(dir.getAbsolutePath(), BACKUP_DIR).toString()); if (!backupDir.exists()) if (!backupDir.mkdir()) log.warn("make dir failed.\nBackupDir=" + backupDir.getAbsolutePath()); @@ -72,8 +75,21 @@ public class FileUtil { } } + public static File getLatestBackupFile(File dir, String fileName) { + File backupDir = new File(Paths.get(dir.getAbsolutePath(), BACKUP_DIR).toString()); + if (!backupDir.exists()) return null; + String dirName = "backups_" + fileName; + if (dirName.contains(".")) dirName = dirName.replace(".", "_"); + File backupFileDir = new File(Paths.get(backupDir.getAbsolutePath(), dirName).toString()); + if (!backupFileDir.exists()) return null; + File[] files = backupFileDir.listFiles(); + if (files == null || files.length == 0) return null; + Arrays.sort(files, Comparator.comparing(File::getName)); + return files[files.length - 1]; + } + public static void deleteRollingBackup(File dir, String fileName) { - File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString()); + File backupDir = new File(Paths.get(dir.getAbsolutePath(), BACKUP_DIR).toString()); if (!backupDir.exists()) return; String dirName = "backups_" + fileName; if (dirName.contains(".")) dirName = dirName.replace(".", "_"); diff --git a/core/src/main/java/haveno/core/api/XmrConnectionService.java b/core/src/main/java/haveno/core/api/XmrConnectionService.java index 48538ef4..4465fd2a 100644 --- a/core/src/main/java/haveno/core/api/XmrConnectionService.java +++ b/core/src/main/java/haveno/core/api/XmrConnectionService.java @@ -99,9 +99,10 @@ public final class XmrConnectionService { @Getter private MoneroDaemonInfo lastInfo; private Long lastLogPollErrorTimestamp; - private Long syncStartHeight = null; + private long lastLogDaemonNotSyncedTimestamp; + private Long syncStartHeight; private TaskLooper daemonPollLooper; - private long lastRefreshPeriodMs = 0; + private long lastRefreshPeriodMs; @Getter private boolean isShutDownStarted; private List listeners = new ArrayList<>(); @@ -371,7 +372,6 @@ public final class XmrConnectionService { Long targetHeight = getTargetHeight(); if (targetHeight == null) return false; if (targetHeight - chainHeight.get() <= 3) return true; // synced if within 3 blocks of target height - log.warn("Our chain height: {} is out of sync with peer nodes chain height: {}", chainHeight.get(), targetHeight); return false; } @@ -720,7 +720,7 @@ public final class XmrConnectionService { } // log error message periodically - if ((lastLogPollErrorTimestamp == null || System.currentTimeMillis() - lastLogPollErrorTimestamp > HavenoUtils.LOG_POLL_ERROR_PERIOD_MS)) { + if (lastLogPollErrorTimestamp == null || System.currentTimeMillis() - lastLogPollErrorTimestamp > HavenoUtils.LOG_POLL_ERROR_PERIOD_MS) { log.warn("Failed to fetch daemon info, trying to switch to best connection: " + e.getMessage()); if (DevEnv.isDevMode()) e.printStackTrace(); lastLogPollErrorTimestamp = System.currentTimeMillis(); @@ -734,6 +734,12 @@ public final class XmrConnectionService { // connected to daemon isConnected = true; + // throttle warnings if daemon not synced + if (!isSyncedWithinTolerance() && System.currentTimeMillis() - lastLogDaemonNotSyncedTimestamp > HavenoUtils.LOG_DAEMON_NOT_SYNCED_WARN_PERIOD_MS) { + log.warn("Our chain height: {} is out of sync with peer nodes chain height: {}", chainHeight.get(), getTargetHeight()); + lastLogDaemonNotSyncedTimestamp = System.currentTimeMillis(); + } + // announce connection change if refresh period changes if (getRefreshPeriodMs() != lastRefreshPeriodMs) { lastRefreshPeriodMs = getRefreshPeriodMs(); diff --git a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java index 7bfbda31..4b44a810 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java @@ -87,7 +87,7 @@ public class MakerReserveOfferFunds extends Task { //if (true) throw new RuntimeException("Pretend error"); reserveTx = model.getXmrWalletService().createReserveTx(penaltyFee, makerFee, sendAmount, securityDeposit, returnAddress, openOffer.isReserveExactAmount(), preferredSubaddressIndex); } catch (Exception e) { - log.warn("Error creating reserve tx, offerId={}, attempt={}/{}, error={}", i + 1, TradeProtocol.MAX_ATTEMPTS, openOffer.getShortId(), e.getMessage()); + log.warn("Error creating reserve tx, offerId={}, attempt={}/{}, error={}", openOffer.getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); model.getXmrWalletService().handleWalletError(e, sourceConnection); verifyPending(); if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; diff --git a/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationManager.java b/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationManager.java index 0ac6aa43..8082aad4 100644 --- a/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationManager.java +++ b/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationManager.java @@ -511,6 +511,7 @@ public final class ArbitrationManager extends DisputeManager HavenoUtils.LOG_DAEMON_NOT_SYNCED_WARN_PERIOD_MS) { + log.warn("Monero daemon is not synced within tolerance, height={}, targetHeight={}, monerod={}", xmrConnectionService.chainHeightProperty().get(), xmrConnectionService.getTargetHeight(), xmrConnectionService.getConnection() == null ? null : xmrConnectionService.getConnection().getUri()); + lastLogDaemonNotSyncedTimestamp = System.currentTimeMillis(); + } return; } + // sync wallet if behind daemon if (walletHeight.get() < xmrConnectionService.getTargetHeight()) { synchronized (walletLock) { // avoid long sync from blocking other operations diff --git a/desktop/package/macosx/Info.plist b/desktop/package/macosx/Info.plist index 29c4932b..5a058b31 100644 --- a/desktop/package/macosx/Info.plist +++ b/desktop/package/macosx/Info.plist @@ -5,10 +5,10 @@ CFBundleVersion - 1.0.10 + 1.0.11 CFBundleShortVersionString - 1.0.10 + 1.0.11 CFBundleExecutable Haveno diff --git a/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java b/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java index 0fa45624..cc5a7cd1 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java @@ -242,8 +242,12 @@ public class WithdrawalView extends ActivatableView { if (GUIUtil.isReadyForTxBroadcastOrShowPopup(xmrWalletService)) { try { + // collect tx fields to local variables + String withdrawToAddress = withdrawToTextField.getText(); + boolean sendMax = this.sendMax; + BigInteger amount = this.amount; + // validate address - final String withdrawToAddress = withdrawToTextField.getText(); if (!MoneroUtils.isValidAddress(withdrawToAddress, XmrWalletService.getMoneroNetworkType())) { throw new IllegalArgumentException(Res.get("validation.xmr.invalidAddress")); } @@ -298,7 +302,7 @@ public class WithdrawalView extends ActivatableView { BigInteger receiverAmount = tx.getOutgoingTransfer().getDestinations().get(0).getAmount(); BigInteger fee = tx.getFee(); String messageText = Res.get("shared.sendFundsDetailsWithFee", - HavenoUtils.formatXmr(amount, true), + HavenoUtils.formatXmr(receiverAmount.add(fee), true), withdrawToAddress, HavenoUtils.formatXmr(fee, true), HavenoUtils.formatXmr(receiverAmount, true)); diff --git a/docs/create-mainnet.md b/docs/create-mainnet.md index 32606a0e..38c211d4 100644 --- a/docs/create-mainnet.md +++ b/docs/create-mainnet.md @@ -57,6 +57,12 @@ For example, change "Haveno" to "HavenoX", which will use this application folde - macOS: ~/Library/Application Support/HavenoX/ - Windows: ~\AppData\Roaming\HavenoX\ +## Change the P2P network version + +To avoid interference with other networks, change `P2P_NETWORK_VERSION` in [Version.java](https://github.com/haveno-dex/haveno/blob/a7e90395d24ec3d33262dd5d09c5faec61651a51/common/src/main/java/haveno/common/app/Version.java#L83). + +For example, change it to `"B"`. + ## Start the seed nodes Rebuild for the previous changes to the source code to take effect: `make skip-tests`. diff --git a/docs/deployment-guide.md b/docs/deployment-guide.md index ce538319..2f7590d0 100644 --- a/docs/deployment-guide.md +++ b/docs/deployment-guide.md @@ -219,6 +219,12 @@ For example, change "Haveno" to "HavenoX", which will use this application folde - macOS: ~/Library/Application Support/HavenoX/ - Windows: ~\AppData\Roaming\HavenoX\ +## Change the P2P network version + +To avoid interference with other networks, change `P2P_NETWORK_VERSION` in [Version.java](https://github.com/haveno-dex/haveno/blob/a7e90395d24ec3d33262dd5d09c5faec61651a51/common/src/main/java/haveno/common/app/Version.java#L83). + +For example, change it to `"B"`. + ## Set the network's release date Optionally set the network's approximate release date by setting `RELEASE_DATE` in HavenoUtils.java. diff --git a/docs/installing.md b/docs/installing.md index f779d8ef..dcf9c81d 100644 --- a/docs/installing.md +++ b/docs/installing.md @@ -1,18 +1,19 @@ -# Set up environment +# Build and run Haveno -These are the steps needed to build Haveno and test it on our test network or locally. +These are the steps needed to build and run Haveno. You can test it locally or on our test network using the official Haveno repository. + +> [!note] +> Trying to use Haveno on mainnet? +> +> The official Haveno repository does not operate or endorse any mainnet network. +> +> Find a third party network and use their installer or build their repository. Alternatively [create your own mainnet network](create-mainnet.md). ## Install dependencies -On Linux and macOS, install Java JDK 21: - -``` -curl -s "https://get.sdkman.io" | bash -sdk install java 21.0.2.fx-librca -``` - -On Windows, install MSYS2 and Java JDK 21: +On Ubuntu: `sudo apt install make wget git` +On Windows, first install MSYS2: 1. Install [MSYS2](https://www.msys2.org/). 2. Start MSYS2 MINGW64 or MSYS MINGW32 depending on your system. Use MSYS2 for all commands throughout this document. 4. Update pacman: `pacman -Syy` @@ -21,12 +22,17 @@ On Windows, install MSYS2 and Java JDK 21: 64-bit: `pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake git` 32-bit: `pacman -S mingw-w64-i686-toolchain make mingw-w64-i686-cmake git` - 6. `curl -s "https://get.sdkman.io" | bash` - 7. `sdk install java 21.0.2.fx-librca` + +On all platforms, install Java JDK 21: + +``` +curl -s "https://get.sdkman.io" | bash +sdk install java 21.0.2.fx-librca +``` ## Build Haveno -If it's the first time you are building Haveno, run the following commands to download the repository, the needed dependencies, and build the latest release: +If it's the first time you are building Haveno, run the following commands to download the repository, the needed dependencies, and build the latest release. If using a third party network, replace the repository URL with theirs: ``` git clone https://github.com/haveno-dex/haveno.git @@ -45,15 +51,23 @@ git pull make clean && make ``` -Make sure to delete the folder with the local settings, as there are breaking changes between releases: +## Run Haveno -On **Linux**: remove everything inside `~/.local/share/haveno-*/xmr_stagenet/`, except the `wallet` folder. +> [!note] +> When you run Haveno, your application folder will be installed to: +> * Linux: `~/.local/share/Haveno/` +> * macOS: `~/Library/Application\ Support/Haveno/` +> * Windows: `~\AppData\Roaming\Haveno\` -On **Mac**: remove everything inside `~/Library/Application\ Support/haveno-*/xmr_stagenet/`, except the `wallet` folder. +### Mainnet -On **Windows**: remove everything inside `~\AppData\Roaming\haveno-*/xmr_stagenet/`, except the `wallet` folder. +If you are building a third party repository which supports mainnet, you can start Haveno with: -## Join the public test network +``` +make haveno-desktop-mainnet +``` + +### Join the public test network If you want to try Haveno in a live setup, launch a Haveno instance that will connect to other peers on our public test environment, which runs on Monero's stagenet (you won't need to download the blockchain locally). You'll be able to make test trades with other users and have a preview of Haveno's trade protocol in action. Note that development is very much ongoing. Things are slow and might break. @@ -67,11 +81,11 @@ Steps: 6. Now if you are taking a trade you'll be asked to confirm you have sent the payment outside Haveno. Confirm in the app and wait for the confirmation of received payment from the other trader. 7. Once the other trader confirms, deposits are sent back to the owners and the trade is complete. -# Run a local test network +### Run a local test network If you are a developer who wants to test Haveno in a more controlled way, follow the next steps to build a local test environment. -## Run a local XMR testnet +#### Run a local XMR testnet 1. In a new terminal window run `make monerod1-local` 1. In a new terminal window run `make monerod2-local` @@ -79,7 +93,7 @@ If you are a developer who wants to test Haveno in a more controlled way, follow `start_mining 9tsUiG9bwcU7oTbAdBwBk2PzxFtysge5qcEsHEpetmEKgerHQa1fDqH7a4FiquZmms7yM22jdifVAD7jAb2e63GSJMuhY75 1` -## Deploy +#### Deploy If you are a *screen* user, simply run `make deploy`. This command will open all needed Haveno instances (seednode, user1, user2, arbitrator) using *screen*. @@ -93,7 +107,7 @@ If you don't use *screen*, open 4 terminal windows and run in each one of them: If this is the first time launching the arbitrator desktop application, register the arbitrator after the interface opens. Go to the *Account* tab and press `cmd+r`. Confirm the registration of the arbitrator. -## Fund your wallets +#### Fund your wallets When running user1 and user2, you'll see a Monero address prompted in the terminal. Send test XMR to the addresses of both user1 and user2 to be able to initiate a trade. @@ -101,6 +115,6 @@ You can fund the two wallets by mining some test XMR coins to those addresses. T monerod will start mining local testnet coins on your device using one thread. Replace `ADDRESS` with the address of user1 first, and then user2's. Run `stop_mining` to stop mining. -## Start testing +#### Start testing You are all set. Now that everything is running and your wallets are funded, you can create test trades between user1 and user2. Remember to mine a few blocks after opening and accepting the test trade so the transaction will be confirmed. diff --git a/docs/user-guide.md b/docs/user-guide.md index a7072ca6..8ea7db1b 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -2,10 +2,24 @@ This document is a guide for Haveno users. -# Running a Local Monero Node +## Running a Local Monero Node For the best experience using Haveno, it is highly recommended to run your own local Monero node to improve security and responsiveness. By default, Haveno will automatically connect to a local node if it is detected. Additionally, Haveno will automatically start and connect to your local Monero node if it was last used and is currently offline. -Otherwise, Haveno will connect to a pre-configured remote node, unless manually configured otherwise. \ No newline at end of file +Otherwise, Haveno will connect to a pre-configured remote node, unless manually configured otherwise. + +## UI Scaling For High DPI Displays + +If the UI is too small on your display, you can force UI scaling to a value of your choice using one of the following approaches. The examples below scale the UI to 200%, you can replace the '2' with a value of your choice, e.g. '1.5' for 150%. + +### Edit The Application Shortcut (KDE Plasma) + +1) Open the properties of your shortcut to haveno +2) Click on Program +3) Add `JAVA_TOOL_OPTIONS=-Dglass.gtk.uiScale=2` to the environment variables + +### Launching From The Command Line + +Prepend `JAVA_TOOL_OPTIONS=-Dglass.gtk.uiScale=2` to the command you use to launch haveno (e.g. `JAVA_TOOL_OPTIONS=-Dglass.gtk.uiScale=2 haveno-desktop`). diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 5e2bf6c5..dc626c93 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -173,14 +173,6 @@ - - - - - - - - diff --git a/media/donate_bitcoin.png b/media/donate_bitcoin.png new file mode 100644 index 00000000..ac25c2c2 Binary files /dev/null and b/media/donate_bitcoin.png differ diff --git a/media/donate_monero.png b/media/donate_monero.png new file mode 100644 index 00000000..35b3e21d Binary files /dev/null and b/media/donate_monero.png differ diff --git a/media/qrbtc.png b/media/qrbtc.png deleted file mode 100644 index 66e90ebd..00000000 Binary files a/media/qrbtc.png and /dev/null differ diff --git a/media/qrhaveno.png b/media/qrhaveno.png deleted file mode 100644 index 347b04a5..00000000 Binary files a/media/qrhaveno.png and /dev/null differ diff --git a/seednode/src/main/java/haveno/seednode/SeedNodeMain.java b/seednode/src/main/java/haveno/seednode/SeedNodeMain.java index dedb7d1c..5659ab2e 100644 --- a/seednode/src/main/java/haveno/seednode/SeedNodeMain.java +++ b/seednode/src/main/java/haveno/seednode/SeedNodeMain.java @@ -41,7 +41,7 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class SeedNodeMain extends ExecutableForAppWithP2p { private static final long CHECK_CONNECTION_LOSS_SEC = 30; - private static final String VERSION = "1.0.10"; + private static final String VERSION = "1.0.11"; private SeedNode seedNode; private Timer checkConnectionLossTime; diff --git a/seednode/torrc b/seednode/torrc index d90b0111..d6e2c55b 100644 --- a/seednode/torrc +++ b/seednode/torrc @@ -124,8 +124,8 @@ HiddenServiceEnableIntroDoSDefense 1 ## Proof of Work (PoW) before establishing Rendezvous Circuits ## The lower the queue and burst rates, the higher the puzzle effort tends to be for users. HiddenServicePoWDefensesEnabled 1 -HiddenServicePoWQueueRate 200 # (Default: 250) -HiddenServicePoWQueueBurst 1000 # (Default: 2500) +HiddenServicePoWQueueRate 50 # (Default: 250) +HiddenServicePoWQueueBurst 250 # (Default: 2500) ## Stream limits in the established Rendezvous Circuits ## The maximum number of simultaneous streams (connections) per rendezvous circuit. The max value allowed is 65535. (0 = unlimited) @@ -143,8 +143,8 @@ HiddenServiceEnableIntroDoSDefense 1 #HiddenServiceNumIntroductionPoints 3 # (Default: 3) HiddenServicePoWDefensesEnabled 1 -HiddenServicePoWQueueRate 200 # (Default: 250) -HiddenServicePoWQueueBurst 1000 # (Default: 2500) +HiddenServicePoWQueueRate 50 # (Default: 250) +HiddenServicePoWQueueBurst 250 # (Default: 2500) HiddenServiceMaxStreams 25 #HiddenServiceMaxStreamsCloseCircuit 1