From 61a62a1d942babbdb57da9eedc966376a29b0fdd Mon Sep 17 00:00:00 2001 From: boldsuck <git@boldsuck.de> Date: Sun, 9 Mar 2025 01:42:53 +0100 Subject: [PATCH 01/21] Update tor-upgrade.md docu (#1645) --- docs/tor-upgrade.md | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/docs/tor-upgrade.md b/docs/tor-upgrade.md index 990cc5d161..cf7548207f 100644 --- a/docs/tor-upgrade.md +++ b/docs/tor-upgrade.md @@ -10,7 +10,7 @@ As per the project's authors, `netlayer` is _"essentially a wrapper around the o easy use and convenient integration into Kotlin/Java projects"_. Similarly, `tor-binary` is _"[the] Tor binary packaged in a way that can be used for java projects"_. The project -unpacks the tor browser binaries to extract and repackage the tor binaries themselves. +unpacks the Tor Browser binaries to extract and repackage the tor binaries themselves. Therefore, upgrading tor in Haveno comes down to upgrading these two artefacts. @@ -22,8 +22,8 @@ Therefore, upgrading tor in Haveno comes down to upgrading these two artefacts. - Find out which tor version Haveno currently uses - Find out the current `netlayer` version (see `netlayerVersion` in `haveno/build.gradle`) - - Find that release on the project's [releases page][3] - - The release description says which tor version it includes + - Find that tag on the project's [Tags page][3] + - The tag description says which tor version it includes - Find out the latest available tor release - See the [official tor changelog][4] @@ -32,23 +32,24 @@ Therefore, upgrading tor in Haveno comes down to upgrading these two artefacts. During this update, you will need to keep track of: - - the new tor browser version + - the new Tor Browser version - the new tor binary version Create a PR for the `master` branch of [tor-binary][2] with the following changes: - - Decide which tor browser version contains the desired tor binary version - - The official tor browser releases are here: https://dist.torproject.org/torbrowser/ - - For the chosen tor browser version, get the list of SHA256 checksums and its signature - - For example, for tor browser 10.0.12: - - https://dist.torproject.org/torbrowser/10.0.12/sha256sums-signed-build.txt - - https://dist.torproject.org/torbrowser/10.0.12/sha256sums-signed-build.txt.asc + - Decide which Tor Browser version contains the desired tor binary version + - The latest official Tor Browser releases are here: https://dist.torproject.org/torbrowser/ + - All official Tor Browser releases are here: https://archive.torproject.org/tor-package-archive/torbrowser/ + - For the chosen Tor Browser version, get the list of SHA256 checksums and its signature + - For example, for Tor Browser 14.0.7: + - https://dist.torproject.org/torbrowser/14.0.7/sha256sums-signed-build.txt + - https://dist.torproject.org/torbrowser/14.0.7/sha256sums-signed-build.txt.asc - Verify the signature of the checksums list (see [instructions][5]) - Update the `tor-binary` checksums - For each file present in `tor-binary/tor-binary-resources/checksums`: - - Rename the file such that it reflects the new tor browser version, but preserves the naming scheme + - Rename the file such that it reflects the new Tor Browser version, but preserves the naming scheme - Update the contents of the file with the corresponding SHA256 checksum from the list - - Update `torbrowser.version` to the new tor browser version in: + - Update `torbrowser.version` to the new Tor Browser version in: - `tor-binary/build.xml` - `tor-binary/pom.xml` - Update `version` to the new tor binary version in: @@ -72,7 +73,7 @@ next. ### 3. Update `netlayer` -Create a PR for the `externaltor` branch of [netlayer][1] with the following changes: +Create a PR for the `master` branch of [netlayer][1] with the following changes: - In `netlayer/pom.xml`: - Update `tor-binary.version` to the `tor-binary` commit ID from above (e.g. `a4b868a`) @@ -82,13 +83,13 @@ Create a PR for the `externaltor` branch of [netlayer][1] with the following cha - `netlayer/tor.external/pom.xml` - `netlayer/tor.native/pom.xml` -Once the PR is merged, make a note of the commit ID in the `externaltor` branch (for example `32779ac`), as it will be +Once the PR is merged, make a note of the commit ID in the `master` branch (for example `32779ac`), as it will be needed next. Create a tag for the new artefact version, having the new tor binary version as description, for example: ``` -# Create tag locally for new netlayer release, on the externaltor branch +# Create tag locally for new netlayer release, on the master branch git tag -s 0.7.0 -m"tor 0.4.5.6" # Push it to netlayer repo @@ -105,8 +106,6 @@ Create a Haveno PR with the following changes: - See instructions in `haveno/gradle/witness/gradle-witness.gradle` - - ## Credits Thanks to freimair, JesusMcCloud, mrosseel, sschuberth and cedricwalter for their work on the original @@ -115,8 +114,8 @@ Thanks to freimair, JesusMcCloud, mrosseel, sschuberth and cedricwalter for thei -[1]: https://github.com/bisq-network/netlayer "netlayer" -[2]: https://github.com/bisq-network/tor-binary "tor-binary" -[3]: https://github.com/bisq-network/netlayer/releases "netlayer releases" +[1]: https://github.com/haveno-dex/netlayer "netlayer" +[2]: https://github.com/haveno-dex/tor-binary "tor-binary" +[3]: https://github.com/haveno-dex/netlayer/tags "netlayer Tags" [4]: https://gitweb.torproject.org/tor.git/plain/ChangeLog "tor changelog" [5]: https://support.torproject.org/tbb/how-to-verify-signature/ "verify tor signature" From 03a1132c2f9e7a11a7af2a119e22e7976c00ddc3 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Sat, 8 Mar 2025 06:23:55 -0500 Subject: [PATCH 02/21] copy monero payment uri to clipboard in qr code window --- .../java/haveno/desktop/main/overlays/Overlay.java | 9 ++++++--- .../desktop/main/overlays/windows/QRCodeWindow.java | 10 +++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/Overlay.java b/desktop/src/main/java/haveno/desktop/main/overlays/Overlay.java index 4d0eb57fea..e216b14ed9 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/Overlay.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/Overlay.java @@ -765,9 +765,7 @@ public abstract class Overlay<T extends Overlay<T>> { FormBuilder.getIconForLabel(AwesomeIcon.COPY, copyIcon, "1.1em"); copyIcon.addEventHandler(MOUSE_CLICKED, mouseEvent -> { if (message != null) { - String forClipboard = headLineLabel.getText() + System.lineSeparator() + message - + System.lineSeparator() + (messageHyperlinks == null ? "" : messageHyperlinks.toString()); - Utilities.copyToClipboard(forClipboard); + Utilities.copyToClipboard(getClipboardText()); Tooltip tp = new Tooltip(Res.get("shared.copiedToClipboard")); Node node = (Node) mouseEvent.getSource(); UserThread.runAfter(() -> tp.hide(), 1); @@ -1083,6 +1081,11 @@ public abstract class Overlay<T extends Overlay<T>> { return isDisplayed; } + public String getClipboardText() { + return headLineLabel.getText() + System.lineSeparator() + message + + System.lineSeparator() + (messageHyperlinks == null ? "" : messageHyperlinks.toString()); + } + @Override public String toString() { return "Popup{" + diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/QRCodeWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/QRCodeWindow.java index 223933e5c1..8bca62d143 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/QRCodeWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/QRCodeWindow.java @@ -37,10 +37,10 @@ import java.io.ByteArrayInputStream; public class QRCodeWindow extends Overlay<QRCodeWindow> { private static final Logger log = LoggerFactory.getLogger(QRCodeWindow.class); private final ImageView qrCodeImageView; - private final String bitcoinURI; + private final String moneroUri; public QRCodeWindow(String bitcoinURI) { - this.bitcoinURI = bitcoinURI; + this.moneroUri = bitcoinURI; final byte[] imageBytes = QRCode .from(bitcoinURI) .withSize(300, 300) @@ -70,7 +70,7 @@ public class QRCodeWindow extends Overlay<QRCodeWindow> { GridPane.setHalignment(qrCodeImageView, HPos.CENTER); gridPane.getChildren().add(qrCodeImageView); - String request = bitcoinURI.replace("%20", " ").replace("?", "\n?").replace("&", "\n&"); + String request = moneroUri.replace("%20", " ").replace("?", "\n?").replace("&", "\n&"); Label infoLabel = new AutoTooltipLabel(Res.get("qRCodeWindow.request", request)); infoLabel.setMouseTransparent(true); infoLabel.setWrapText(true); @@ -87,4 +87,8 @@ public class QRCodeWindow extends Overlay<QRCodeWindow> { applyStyles(); display(); } + + public String getClipboardText() { + return moneroUri; + } } From e5f729d12f8389a50a0a3b6113ec23f56ac3ed44 Mon Sep 17 00:00:00 2001 From: boldsuck <git@boldsuck.de> Date: Sun, 9 Mar 2025 19:32:32 +0100 Subject: [PATCH 03/21] Update Tor Browser version: 14.0.7 and tor binary version: 0.4.8.14 (#1650) --- build.gradle | 2 +- gradle/verification-metadata.xml | 48 ++++++++++++++++---------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/build.gradle b/build.gradle index 74e776cb2b..e083e8ec08 100644 --- a/build.gradle +++ b/build.gradle @@ -71,7 +71,7 @@ configure(subprojects) { loggingVersion = '1.2' lombokVersion = '1.18.30' mockitoVersion = '5.10.0' - netlayerVersion = '700ec94f0f' // Tor browser version 14.0.3 and tor binary version: 0.4.8.13 + netlayerVersion = 'd4f9d0ce24' // Tor browser version 14.0.7 and tor binary version: 0.4.8.14 protobufVersion = '3.19.1' protocVersion = protobufVersion pushyVersion = '0.13.2' diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 069e08177b..cbfb839d9f 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -205,44 +205,44 @@ <sha256 value="d4ea711258c783e0accb8feaaa204f0414781551b0159fa17e5f1869200f96f7" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.haveno-dex.netlayer" name="tor" version="700ec94f0f"> - <artifact name="tor-700ec94f0f.jar"> - <sha256 value="63eafc2bf43ae2556d5a24f23b5ddfe371c1ac01b7bc595d6fdb7eadcba37d52" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.netlayer" name="tor" version="d4f9d0ce24"> + <artifact name="tor-d4f9d0ce24.jar"> + <sha256 value="58c7df7cab675ec3db4f80b456282d49e8d983676af7f053c7514fc5dfb83cee" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.haveno-dex.netlayer" name="tor.external" version="700ec94f0f"> - <artifact name="tor.external-700ec94f0f.jar"> - <sha256 value="01b506ec84697a08abfad2ab1928a8ba8bda36f588f05fbb14e5b9cacdbd0e3d" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.netlayer" name="tor.external" version="d4f9d0ce24"> + <artifact name="tor.external-d4f9d0ce24.jar"> + <sha256 value="1231429367e83f7c7536cf6febd4df2e95fec81a776f199791d5b9790aa1d25e" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.haveno-dex.netlayer" name="tor.native" version="700ec94f0f"> - <artifact name="tor.native-700ec94f0f.jar"> - <sha256 value="51886b73f9c41d1d16ab7995af9846f67d6f7942def0c182b56a2a801ae301d3" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.netlayer" name="tor.native" version="d4f9d0ce24"> + <artifact name="tor.native-d4f9d0ce24.jar"> + <sha256 value="5d83e8fb429e0fe79df55b220731567b9290f84bd2f1ee03b2a194284290e052" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.haveno-dex.tor-binary" name="tor-binary-geoip" version="6bdcb0303ae92f4b7bd7102706467f10fcac4d9e"> - <artifact name="tor-binary-geoip-6bdcb0303ae92f4b7bd7102706467f10fcac4d9e.jar"> - <sha256 value="7bd0fa5e818825d8f0c87a52cc0c468a06fd7850c825b9b36ba82d7a3d9f2fa5" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.tor-binary" name="tor-binary-geoip" version="462c44c157cbf0b7574b7ab14d0bf231df770a63"> + <artifact name="tor-binary-geoip-462c44c157cbf0b7574b7ab14d0bf231df770a63.jar"> + <sha256 value="af2c7a517d45c7640f11c28fa5987201ddcb4ea139ef4d56fbcff17336a83289" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.haveno-dex.tor-binary" name="tor-binary-linux32" version="6bdcb0303ae92f4b7bd7102706467f10fcac4d9e"> - <artifact name="tor-binary-linux32-6bdcb0303ae92f4b7bd7102706467f10fcac4d9e.jar"> - <sha256 value="4b4b3d822d8ad88f874450385751d0b26b41e2724d0d9b703acd9e4b73b3ba5d" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.tor-binary" name="tor-binary-linux32" version="462c44c157cbf0b7574b7ab14d0bf231df770a63"> + <artifact name="tor-binary-linux32-462c44c157cbf0b7574b7ab14d0bf231df770a63.jar"> + <sha256 value="6ee4cb8f9cd33bb255fa0e9991e9be49338f574999270434a4499b4554e5e714" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.haveno-dex.tor-binary" name="tor-binary-linux64" version="6bdcb0303ae92f4b7bd7102706467f10fcac4d9e"> - <artifact name="tor-binary-linux64-6bdcb0303ae92f4b7bd7102706467f10fcac4d9e.jar"> - <sha256 value="512b6d52217feed0efe84c1f43888fc8a8ba32a8998486c32e233a031dddbd94" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.tor-binary" name="tor-binary-linux64" version="462c44c157cbf0b7574b7ab14d0bf231df770a63"> + <artifact name="tor-binary-linux64-462c44c157cbf0b7574b7ab14d0bf231df770a63.jar"> + <sha256 value="7da86fc024976ab46b6e92f4f5c0046b7df1f800cd09f297232698b1a6b7f961" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.haveno-dex.tor-binary" name="tor-binary-macos" version="6bdcb0303ae92f4b7bd7102706467f10fcac4d9e"> - <artifact name="tor-binary-macos-6bdcb0303ae92f4b7bd7102706467f10fcac4d9e.jar"> - <sha256 value="f68f9c6a3f56d084bd9426ff3834bcc90b07a4489357b04ef8151465a73c8783" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.tor-binary" name="tor-binary-macos" version="462c44c157cbf0b7574b7ab14d0bf231df770a63"> + <artifact name="tor-binary-macos-462c44c157cbf0b7574b7ab14d0bf231df770a63.jar"> + <sha256 value="f1cd51f9acf7562190fc1ea327325116fcd006f98e16eaef279554f20cca86c3" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.haveno-dex.tor-binary" name="tor-binary-windows" version="6bdcb0303ae92f4b7bd7102706467f10fcac4d9e"> - <artifact name="tor-binary-windows-6bdcb0303ae92f4b7bd7102706467f10fcac4d9e.jar"> - <sha256 value="94f7090f34dc6f12cdd5e5a247f7f0c4aeb40693258fd5365db41a2b8a71b197" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.tor-binary" name="tor-binary-windows" version="462c44c157cbf0b7574b7ab14d0bf231df770a63"> + <artifact name="tor-binary-windows-462c44c157cbf0b7574b7ab14d0bf231df770a63.jar"> + <sha256 value="39ae9a91803dae23fc5573f46f136b4ee973babfd72c3495963f1c430d20f162" origin="Generated by Gradle"/> </artifact> </component> <component group="com.github.johnrengelman" name="shadow" version="8.1.1"> From c853c4ffcb0579625f630ef83f0af4c1957e8e97 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Sun, 9 Mar 2025 16:54:28 -0400 Subject: [PATCH 04/21] bump version to 1.0.19 --- build.gradle | 2 +- common/src/main/java/haveno/common/app/Version.java | 2 +- desktop/package/linux/exchange.haveno.Haveno.metainfo.xml | 2 +- desktop/package/macosx/Info.plist | 4 ++-- docs/deployment-guide.md | 2 +- seednode/src/main/java/haveno/seednode/SeedNodeMain.java | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index e083e8ec08..3c3d95d074 100644 --- a/build.gradle +++ b/build.gradle @@ -610,7 +610,7 @@ configure(project(':desktop')) { apply plugin: 'com.github.johnrengelman.shadow' apply from: 'package/package.gradle' - version = '1.0.18-SNAPSHOT' + version = '1.0.19-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 d39016dc31..74f3ceb9d6 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.18"; + public static final String VERSION = "1.0.19"; /** * Holds a list of the tagged resource files for optimizing the getData requests. diff --git a/desktop/package/linux/exchange.haveno.Haveno.metainfo.xml b/desktop/package/linux/exchange.haveno.Haveno.metainfo.xml index a298688669..fc5f50c2b5 100644 --- a/desktop/package/linux/exchange.haveno.Haveno.metainfo.xml +++ b/desktop/package/linux/exchange.haveno.Haveno.metainfo.xml @@ -60,6 +60,6 @@ </content_rating> <releases> - <release version="1.0.18" date="2025-01-19"/> + <release version="1.0.19" date="2025-03-10"/> </releases> </component> diff --git a/desktop/package/macosx/Info.plist b/desktop/package/macosx/Info.plist index 7693e124b7..a24f430c12 100644 --- a/desktop/package/macosx/Info.plist +++ b/desktop/package/macosx/Info.plist @@ -5,10 +5,10 @@ <!-- See: https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html --> <key>CFBundleVersion</key> - <string>1.0.18</string> + <string>1.0.19</string> <key>CFBundleShortVersionString</key> - <string>1.0.18</string> + <string>1.0.19</string> <key>CFBundleExecutable</key> <string>Haveno</string> diff --git a/docs/deployment-guide.md b/docs/deployment-guide.md index 42f89b115b..67b5236d33 100644 --- a/docs/deployment-guide.md +++ b/docs/deployment-guide.md @@ -270,7 +270,7 @@ Then follow these instructions: https://github.com/haveno-dex/haveno/blob/master <b>Set the mandatory minimum version for trading (optional)</b> -If applicable, update the mandatory minimum version for trading, by entering `ctrl + f` to open the Filter window, enter a private key with developer privileges, and enter the minimum version (e.g. 1.0.18) in the field labeled "Min. version required for trading". +If applicable, update the mandatory minimum version for trading, by entering `ctrl + f` to open the Filter window, enter a private key with developer privileges, and enter the minimum version (e.g. 1.0.19) in the field labeled "Min. version required for trading". <b>Send update alert</b> diff --git a/seednode/src/main/java/haveno/seednode/SeedNodeMain.java b/seednode/src/main/java/haveno/seednode/SeedNodeMain.java index 281e138c0b..35d4bbbe17 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.18"; + private static final String VERSION = "1.0.19"; private SeedNode seedNode; private Timer checkConnectionLossTime; From 9acd7ad584c62c4123bc8f47ccf7ca7e32ce734f Mon Sep 17 00:00:00 2001 From: woodser <woodser@protonmail.com> Date: Sun, 9 Mar 2025 17:02:15 -0400 Subject: [PATCH 05/21] rename config handler from btc to xmr --- core/src/main/java/haveno/core/app/HavenoHeadlessApp.java | 2 +- core/src/main/java/haveno/core/app/HavenoSetup.java | 4 ++-- core/src/main/java/haveno/core/app/WalletAppSetup.java | 6 +++--- .../src/main/java/haveno/desktop/main/MainViewModel.java | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/haveno/core/app/HavenoHeadlessApp.java b/core/src/main/java/haveno/core/app/HavenoHeadlessApp.java index 0cf18224ba..fc6eb2d75c 100644 --- a/core/src/main/java/haveno/core/app/HavenoHeadlessApp.java +++ b/core/src/main/java/haveno/core/app/HavenoHeadlessApp.java @@ -86,7 +86,7 @@ public class HavenoHeadlessApp implements HeadlessApp { havenoSetup.setDisplaySecurityRecommendationHandler(key -> log.info("onDisplaySecurityRecommendationHandler")); havenoSetup.setWrongOSArchitectureHandler(msg -> log.error("onWrongOSArchitectureHandler. msg={}", msg)); havenoSetup.setRejectedTxErrorMessageHandler(errorMessage -> log.warn("setRejectedTxErrorMessageHandler. errorMessage={}", errorMessage)); - havenoSetup.setShowPopupIfInvalidBtcConfigHandler(() -> log.error("onShowPopupIfInvalidBtcConfigHandler")); + havenoSetup.setShowPopupIfInvalidXmrConfigHandler(() -> log.error("onShowPopupIfInvalidXmrConfigHandler")); havenoSetup.setRevolutAccountsUpdateHandler(revolutAccountList -> log.info("setRevolutAccountsUpdateHandler: revolutAccountList={}", revolutAccountList)); havenoSetup.setOsxKeyLoggerWarningHandler(() -> log.info("setOsxKeyLoggerWarningHandler")); havenoSetup.setQubesOSInfoHandler(() -> log.info("setQubesOSInfoHandler")); diff --git a/core/src/main/java/haveno/core/app/HavenoSetup.java b/core/src/main/java/haveno/core/app/HavenoSetup.java index eee13f3eec..6637511298 100644 --- a/core/src/main/java/haveno/core/app/HavenoSetup.java +++ b/core/src/main/java/haveno/core/app/HavenoSetup.java @@ -176,7 +176,7 @@ public class HavenoSetup { private Consumer<PrivateNotificationPayload> displayPrivateNotificationHandler; @Setter @Nullable - private Runnable showPopupIfInvalidBtcConfigHandler; + private Runnable showPopupIfInvalidXmrConfigHandler; @Setter @Nullable private Consumer<List<RevolutAccount>> revolutAccountsUpdateHandler; @@ -461,7 +461,7 @@ public class HavenoSetup { havenoSetupListeners.forEach(HavenoSetupListener::onInitWallet); walletAppSetup.init(chainFileLockedExceptionHandler, showFirstPopupIfResyncSPVRequestedHandler, - showPopupIfInvalidBtcConfigHandler, + showPopupIfInvalidXmrConfigHandler, () -> {}, () -> {}); } diff --git a/core/src/main/java/haveno/core/app/WalletAppSetup.java b/core/src/main/java/haveno/core/app/WalletAppSetup.java index d17c7ba366..7d37372afd 100644 --- a/core/src/main/java/haveno/core/app/WalletAppSetup.java +++ b/core/src/main/java/haveno/core/app/WalletAppSetup.java @@ -117,7 +117,7 @@ public class WalletAppSetup { void init(@Nullable Consumer<String> chainFileLockedExceptionHandler, @Nullable Runnable showFirstPopupIfResyncSPVRequestedHandler, - @Nullable Runnable showPopupIfInvalidBtcConfigHandler, + @Nullable Runnable showPopupIfInvalidXmrConfigHandler, Runnable downloadCompleteHandler, Runnable walletInitializedHandler) { log.info("Initialize WalletAppSetup with monero-java v{}", MoneroUtils.getVersion()); @@ -199,8 +199,8 @@ public class WalletAppSetup { walletInitializedHandler.run(); }, exception -> { - if (exception instanceof InvalidHostException && showPopupIfInvalidBtcConfigHandler != null) { - showPopupIfInvalidBtcConfigHandler.run(); + if (exception instanceof InvalidHostException && showPopupIfInvalidXmrConfigHandler != null) { + showPopupIfInvalidXmrConfigHandler.run(); } else { walletServiceException.set(exception); } diff --git a/desktop/src/main/java/haveno/desktop/main/MainViewModel.java b/desktop/src/main/java/haveno/desktop/main/MainViewModel.java index f120b794e7..670543a7aa 100644 --- a/desktop/src/main/java/haveno/desktop/main/MainViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/MainViewModel.java @@ -420,7 +420,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener havenoSetup.setRejectedTxErrorMessageHandler(msg -> new Popup().width(850).warning(msg).show()); - havenoSetup.setShowPopupIfInvalidBtcConfigHandler(this::showPopupIfInvalidBtcConfig); + havenoSetup.setShowPopupIfInvalidXmrConfigHandler(this::showPopupIfInvalidXmrConfig); havenoSetup.setRevolutAccountsUpdateHandler(revolutAccountList -> { // We copy the array as we will mutate it later @@ -536,7 +536,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener }); } - private void showPopupIfInvalidBtcConfig() { + private void showPopupIfInvalidXmrConfig() { preferences.setMoneroNodesOptionOrdinal(0); new Popup().warning(Res.get("settings.net.warn.invalidXmrConfig")) .hideCloseButton() From 2d46b2ab7c72db58a1ca8be8a3ce288d5a961d06 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Thu, 6 Mar 2025 10:16:23 -0500 Subject: [PATCH 06/21] log warning on error taking offer from ui --- .../haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java index f6b947954d..1a548f1b1f 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java @@ -284,6 +284,7 @@ class TakeOfferDataModel extends OfferDataModel { // handle error if (errorMsg != null) { new Popup().warning(errorMsg).show(); + log.warn("Error taking offer " + offer.getId() + ": " + errorMsg); errorMessageHandler.handleErrorMessage(errorMsg); } } From 8b1d2aa203d4a680fe69ce502955232f9947ebcd Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Thu, 6 Mar 2025 10:53:18 -0500 Subject: [PATCH 07/21] fix bug to delete scheduled failed trade after restart --- core/src/main/java/haveno/core/trade/Trade.java | 13 +++++++++---- .../main/java/haveno/core/trade/TradeManager.java | 8 ++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index 6ad8e7aef3..ed4a8ce8b0 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -1618,15 +1618,16 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { // done if wallet already deleted if (!walletExists()) return; - // move to failed trades - processModel.getTradeManager().onMoveInvalidTradeToFailedTrades(this); - // set error height if (processModel.getTradeProtocolErrorHeight() == 0) { log.warn("Scheduling to remove trade if unfunded for {} {} from height {}", getClass().getSimpleName(), getId(), xmrConnectionService.getLastInfo().getHeight()); - processModel.setTradeProtocolErrorHeight(xmrConnectionService.getLastInfo().getHeight()); + processModel.setTradeProtocolErrorHeight(xmrConnectionService.getLastInfo().getHeight()); // height denotes scheduled error handling } + // move to failed trades + processModel.getTradeManager().onMoveInvalidTradeToFailedTrades(this); + requestPersistence(); + // listen for deposits published to restore trade protocolErrorStateSubscription = EasyBind.subscribe(stateProperty(), state -> { if (isDepositsPublished()) { @@ -1680,6 +1681,10 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { }); } + public boolean isProtocolErrorHandlingScheduled() { + return processModel.getTradeProtocolErrorHeight() > 0; + } + private void restoreDepositsPublishedTrade() { // close open offer diff --git a/core/src/main/java/haveno/core/trade/TradeManager.java b/core/src/main/java/haveno/core/trade/TradeManager.java index caabdb384a..8e5b5d9dd8 100644 --- a/core/src/main/java/haveno/core/trade/TradeManager.java +++ b/core/src/main/java/haveno/core/trade/TradeManager.java @@ -450,8 +450,8 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi return; } - // skip if marked as failed - if (failedTradesManager.getObservableList().contains(trade)) { + // skip if failed and error handling not scheduled + if (failedTradesManager.getObservableList().contains(trade) && !trade.isProtocolErrorHandlingScheduled()) { log.warn("Skipping initialization of failed trade {} {}", trade.getClass().getSimpleName(), trade.getId()); tradesToSkip.add(trade); return; @@ -460,8 +460,8 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi // initialize trade initPersistedTrade(trade); - // remove trade if protocol didn't initialize - if (getOpenTradeByUid(trade.getUid()).isPresent() && !trade.isDepositsPublished()) { + // record if protocol didn't initialize + if (!trade.isDepositsPublished()) { uninitializedTrades.add(trade); } } catch (Exception e) { From bf97fbc7eacd344567bb3302633de67de6658f21 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Fri, 7 Mar 2025 09:43:29 -0500 Subject: [PATCH 08/21] skip reset address entries when failed trade is scheduled for deletion --- core/src/main/java/haveno/core/trade/TradeManager.java | 8 +++++++- .../java/haveno/core/xmr/wallet/XmrWalletService.java | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/haveno/core/trade/TradeManager.java b/core/src/main/java/haveno/core/trade/TradeManager.java index 8e5b5d9dd8..41135e62f1 100644 --- a/core/src/main/java/haveno/core/trade/TradeManager.java +++ b/core/src/main/java/haveno/core/trade/TradeManager.java @@ -923,8 +923,8 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi requestPersistence(); }, errorMessage -> { log.warn("Taker error during trade initialization: " + errorMessage); - xmrWalletService.resetAddressEntriesForOpenOffer(trade.getId()); // TODO: move to maybe remove on error trade.onProtocolError(); + xmrWalletService.resetAddressEntriesForOpenOffer(trade.getId()); // TODO: move this into protocol error handling errorMessageHandler.handleErrorMessage(errorMessage); }); @@ -1285,6 +1285,12 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } } + public boolean hasFailedScheduledTrade(String offerId) { + synchronized (failedTradesManager) { + return failedTradesManager.getTradeById(offerId).isPresent() && failedTradesManager.getTradeById(offerId).get().isProtocolErrorHandlingScheduled(); + } + } + public Optional<Trade> getOpenTradeByUid(String tradeUid) { synchronized (tradableList) { return tradableList.stream().filter(e -> e.getUid().equals(tradeUid)).findFirst(); diff --git a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java index 045897ed37..23e4f74550 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java @@ -1016,6 +1016,13 @@ public class XmrWalletService extends XmrWalletBase { public synchronized void resetAddressEntriesForOpenOffer(String offerId) { log.info("resetAddressEntriesForOpenOffer offerId={}", offerId); + + // skip if failed trade is scheduled for processing // TODO: do not call this function in this case? + if (tradeManager.hasFailedScheduledTrade(offerId)) { + log.warn("Refusing to reset address entries because trade is scheduled for deletion with offerId={}", offerId); + return; + } + swapAddressEntryToAvailable(offerId, XmrAddressEntry.Context.OFFER_FUNDING); // swap trade payout to available if applicable From b0e9627c10ae0a9499d2b802639caba73a30a103 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Sat, 8 Mar 2025 07:55:06 -0500 Subject: [PATCH 09/21] rename openOfferManager.getOpenOffer(id) --- .../java/haveno/core/api/CoreOffersService.java | 2 +- .../java/haveno/core/offer/OpenOfferManager.java | 14 +++++++------- .../dispute/mediation/MediationManager.java | 2 +- .../core/support/dispute/refund/RefundManager.java | 4 ++-- core/src/main/java/haveno/core/trade/Trade.java | 4 ++-- .../main/java/haveno/core/trade/TradeManager.java | 2 +- .../tasks/MaybeSendSignContractRequest.java | 2 +- .../haveno/core/xmr/wallet/XmrWalletService.java | 2 +- .../desktop/main/funds/locked/LockedView.java | 4 ++-- .../desktop/main/funds/reserved/ReservedView.java | 4 ++-- .../desktop/main/offer/MutableOfferViewModel.java | 2 +- .../main/offer/offerbook/OfferBookViewModel.java | 2 +- .../main/overlays/windows/OfferDetailsWindow.java | 2 +- 13 files changed, 23 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/haveno/core/api/CoreOffersService.java b/core/src/main/java/haveno/core/api/CoreOffersService.java index a66388c040..f036fb13ea 100644 --- a/core/src/main/java/haveno/core/api/CoreOffersService.java +++ b/core/src/main/java/haveno/core/api/CoreOffersService.java @@ -159,7 +159,7 @@ public class CoreOffersService { } OpenOffer getMyOffer(String id) { - return openOfferManager.getOpenOfferById(id) + return openOfferManager.getOpenOffer(id) .filter(open -> open.getOffer().isMyOffer(keyRing)) .orElseThrow(() -> new IllegalStateException(format("openoffer with id '%s' not found", id))); diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java index 5df08a38ba..7c71aa9a90 100644 --- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java +++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java @@ -236,7 +236,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe public void onAdded(Offer offer) { // cancel offer if reserved funds spent - Optional<OpenOffer> openOfferOptional = getOpenOfferById(offer.getId()); + Optional<OpenOffer> openOfferOptional = getOpenOffer(offer.getId()); if (openOfferOptional.isPresent() && openOfferOptional.get().getState() != OpenOffer.State.RESERVED && offer.isReservedFundsSpent()) { log.warn("Canceling open offer because reserved funds have been spent, offerId={}, state={}", offer.getId(), openOfferOptional.get().getState()); cancelOpenOffer(openOfferOptional.get(), null, null); @@ -573,7 +573,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe // Remove from offerbook public void removeOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { - Optional<OpenOffer> openOfferOptional = getOpenOfferById(offer.getId()); + Optional<OpenOffer> openOfferOptional = getOpenOffer(offer.getId()); if (openOfferOptional.isPresent()) { cancelOpenOffer(openOfferOptional.get(), resultHandler, errorMessageHandler); } else { @@ -686,7 +686,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe OpenOffer.State originalState, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { - Optional<OpenOffer> openOfferOptional = getOpenOfferById(editedOffer.getId()); + Optional<OpenOffer> openOfferOptional = getOpenOffer(editedOffer.getId()); if (openOfferOptional.isPresent()) { OpenOffer openOffer = openOfferOptional.get(); @@ -750,7 +750,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe // close open offer after key images spent public void closeOpenOffer(Offer offer) { - getOpenOfferById(offer.getId()).ifPresent(openOffer -> { + getOpenOffer(offer.getId()).ifPresent(openOffer -> { removeOpenOffer(openOffer); openOffer.setState(OpenOffer.State.CLOSED); xmrWalletService.resetAddressEntriesForOpenOffer(offer.getId()); @@ -813,14 +813,14 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe return openOffers.getObservableList(); } - public Optional<OpenOffer> getOpenOfferById(String offerId) { + public Optional<OpenOffer> getOpenOffer(String offerId) { synchronized (openOffers) { return openOffers.stream().filter(e -> e.getId().equals(offerId)).findFirst(); } } public boolean hasOpenOffer(String offerId) { - return getOpenOfferById(offerId).isPresent(); + return getOpenOffer(offerId).isPresent(); } public Optional<SignedOffer> getSignedOfferById(String offerId) { @@ -1575,7 +1575,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } try { - Optional<OpenOffer> openOfferOptional = getOpenOfferById(request.offerId); + Optional<OpenOffer> openOfferOptional = getOpenOffer(request.offerId); AvailabilityResult availabilityResult; byte[] makerSignature = null; if (openOfferOptional.isPresent()) { diff --git a/core/src/main/java/haveno/core/support/dispute/mediation/MediationManager.java b/core/src/main/java/haveno/core/support/dispute/mediation/MediationManager.java index b7fa902b83..56686faa61 100644 --- a/core/src/main/java/haveno/core/support/dispute/mediation/MediationManager.java +++ b/core/src/main/java/haveno/core/support/dispute/mediation/MediationManager.java @@ -196,7 +196,7 @@ public final class MediationManager extends DisputeManager<MediationDisputeList> tradeManager.requestPersistence(); } } else { - Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(tradeId); + Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOffer(tradeId); openOfferOptional.ifPresent(openOffer -> openOfferManager.closeOpenOffer(openOffer.getOffer())); } sendAckMessage(chatMessage, dispute.getAgentPubKeyRing(), true, null); diff --git a/core/src/main/java/haveno/core/support/dispute/refund/RefundManager.java b/core/src/main/java/haveno/core/support/dispute/refund/RefundManager.java index fa3503f625..034eac6d5a 100644 --- a/core/src/main/java/haveno/core/support/dispute/refund/RefundManager.java +++ b/core/src/main/java/haveno/core/support/dispute/refund/RefundManager.java @@ -196,7 +196,7 @@ public final class RefundManager extends DisputeManager<RefundDisputeList> { tradeManager.requestPersistence(); } } else { - Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(tradeId); + Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOffer(tradeId); openOfferOptional.ifPresent(openOffer -> openOfferManager.closeOpenOffer(openOffer.getOffer())); } sendAckMessage(chatMessage, dispute.getAgentPubKeyRing(), true, null); @@ -205,7 +205,7 @@ public final class RefundManager extends DisputeManager<RefundDisputeList> { if (tradeManager.getOpenTrade(tradeId).isPresent()) { tradeManager.closeDisputedTrade(tradeId, Trade.DisputeState.REFUND_REQUEST_CLOSED); } else { - Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(tradeId); + Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOffer(tradeId); openOfferOptional.ifPresent(openOffer -> openOfferManager.closeOpenOffer(openOffer.getOffer())); } diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index ed4a8ce8b0..0bc6105049 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -1604,7 +1604,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { } // unreserve maker's open offer - Optional<OpenOffer> openOffer = processModel.getOpenOfferManager().getOpenOfferById(this.getId()); + Optional<OpenOffer> openOffer = processModel.getOpenOfferManager().getOpenOffer(this.getId()); if (this instanceof MakerTrade && openOffer.isPresent()) { processModel.getOpenOfferManager().unreserveOpenOffer(openOffer.get()); } @@ -1688,7 +1688,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { private void restoreDepositsPublishedTrade() { // close open offer - if (this instanceof MakerTrade && processModel.getOpenOfferManager().getOpenOfferById(getId()).isPresent()) { + if (this instanceof MakerTrade && processModel.getOpenOfferManager().getOpenOffer(getId()).isPresent()) { log.info("Closing open offer because {} {} was restored after protocol error", getClass().getSimpleName(), getShortId()); processModel.getOpenOfferManager().closeOpenOffer(checkNotNull(getOffer())); } diff --git a/core/src/main/java/haveno/core/trade/TradeManager.java b/core/src/main/java/haveno/core/trade/TradeManager.java index 41135e62f1..88db590c42 100644 --- a/core/src/main/java/haveno/core/trade/TradeManager.java +++ b/core/src/main/java/haveno/core/trade/TradeManager.java @@ -556,7 +556,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi if (request.getMakerNodeAddress().equals(p2PService.getNetworkNode().getNodeAddress())) { // get open offer - Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(request.getOfferId()); + Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOffer(request.getOfferId()); if (!openOfferOptional.isPresent()) return; OpenOffer openOffer = openOfferOptional.get(); if (openOffer.getState() != OpenOffer.State.AVAILABLE) return; diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java index e1c4cce5cc..1d2170cb53 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java @@ -87,7 +87,7 @@ public class MaybeSendSignContractRequest extends TradeTask { Integer subaddressIndex = null; boolean reserveExactAmount = false; if (trade instanceof MakerTrade) { - reserveExactAmount = processModel.getOpenOfferManager().getOpenOfferById(trade.getId()).get().isReserveExactAmount(); + reserveExactAmount = processModel.getOpenOfferManager().getOpenOffer(trade.getId()).get().isReserveExactAmount(); if (reserveExactAmount) subaddressIndex = model.getXmrWalletService().getAddressEntry(trade.getId(), XmrAddressEntry.Context.OFFER_FUNDING).get().getSubaddressIndex(); } diff --git a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java index 23e4f74550..97aef9545f 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java @@ -1171,7 +1171,7 @@ public class XmrWalletService extends XmrWalletBase { public Stream<XmrAddressEntry> getAddressEntriesForAvailableBalanceStream() { Stream<XmrAddressEntry> available = getFundedAvailableAddressEntries().stream(); available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.ARBITRATOR).stream()); - available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.OFFER_FUNDING).stream().filter(entry -> !tradeManager.getOpenOfferManager().getOpenOfferById(entry.getOfferId()).isPresent())); + available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.OFFER_FUNDING).stream().filter(entry -> !tradeManager.getOpenOfferManager().getOpenOffer(entry.getOfferId()).isPresent())); available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.TRADE_PAYOUT).stream().filter(entry -> tradeManager.getTrade(entry.getOfferId()) == null || tradeManager.getTrade(entry.getOfferId()).isPayoutUnlocked())); return available.filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).compareTo(BigInteger.ZERO) > 0); } diff --git a/desktop/src/main/java/haveno/desktop/main/funds/locked/LockedView.java b/desktop/src/main/java/haveno/desktop/main/funds/locked/LockedView.java index 0a986b5505..8cf5700cc6 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/locked/LockedView.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/locked/LockedView.java @@ -225,8 +225,8 @@ public class LockedView extends ActivatableView<VBox, Void> { Optional<Trade> tradeOptional = tradeManager.getOpenTrade(offerId); if (tradeOptional.isPresent()) { return Optional.of(tradeOptional.get()); - } else if (openOfferManager.getOpenOfferById(offerId).isPresent()) { - return Optional.of(openOfferManager.getOpenOfferById(offerId).get()); + } else if (openOfferManager.getOpenOffer(offerId).isPresent()) { + return Optional.of(openOfferManager.getOpenOffer(offerId).get()); } else { return Optional.empty(); } diff --git a/desktop/src/main/java/haveno/desktop/main/funds/reserved/ReservedView.java b/desktop/src/main/java/haveno/desktop/main/funds/reserved/ReservedView.java index bfa8bd26b0..bcef7e6488 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/reserved/ReservedView.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/reserved/ReservedView.java @@ -224,8 +224,8 @@ public class ReservedView extends ActivatableView<VBox, Void> { Optional<Trade> tradeOptional = tradeManager.getOpenTrade(offerId); if (tradeOptional.isPresent()) { return Optional.of(tradeOptional.get()); - } else if (openOfferManager.getOpenOfferById(offerId).isPresent()) { - return Optional.of(openOfferManager.getOpenOfferById(offerId).get()); + } else if (openOfferManager.getOpenOffer(offerId).isPresent()) { + return Optional.of(openOfferManager.getOpenOffer(offerId).get()); } else { return Optional.<Tradable>empty(); } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java index 5588bb53c0..e32869afe2 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java @@ -665,7 +665,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext createOfferRequested = false; createOfferCanceled = true; OpenOfferManager openOfferManager = HavenoUtils.openOfferManager; - Optional<OpenOffer> openOffer = openOfferManager.getOpenOfferById(offer.getId()); + Optional<OpenOffer> openOffer = openOfferManager.getOpenOffer(offer.getId()); if (openOffer.isPresent()) { openOfferManager.cancelOpenOffer(openOffer.get(), () -> { UserThread.execute(() -> { diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java index d98098e99c..c93dfa8d43 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java @@ -711,6 +711,6 @@ abstract class OfferBookViewModel extends ActivatableViewModel { abstract String getCurrencyCodeFromPreferences(OfferDirection direction); public OpenOffer getOpenOffer(Offer offer) { - return openOfferManager.getOpenOfferById(offer.getId()).orElse(null); + return openOfferManager.getOpenOffer(offer.getId()).orElse(null); } } diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/OfferDetailsWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/OfferDetailsWindow.java index 3ef8ca521b..2139bf2813 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/OfferDetailsWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/OfferDetailsWindow.java @@ -342,7 +342,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> { BigInteger reservedAmount = isMyOffer ? offer.getReservedAmount() : null; // get offer challenge - OpenOffer myOpenOffer = HavenoUtils.openOfferManager.getOpenOfferById(offer.getId()).orElse(null); + OpenOffer myOpenOffer = HavenoUtils.openOfferManager.getOpenOffer(offer.getId()).orElse(null); String offerChallenge = myOpenOffer == null ? null : myOpenOffer.getChallenge(); rows = 3; From bedd38748ea282161d8a33f903cd15940a6d4a59 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Sat, 8 Mar 2025 17:30:31 -0500 Subject: [PATCH 10/21] sign and post offer directly if reserve amount = available balance --- .../haveno/core/offer/OpenOfferManager.java | 67 ++++++++++++------- .../tasks/MakerReserveOfferFunds.java | 3 + .../tasks/MakerSendSignOfferRequest.java | 2 +- .../tasks/TakerReserveTradeFunds.java | 3 + 4 files changed, 49 insertions(+), 26 deletions(-) diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java index 7c71aa9a90..a475691736 100644 --- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java +++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java @@ -987,26 +987,16 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe setSplitOutputTx(openOffer, splitOutputTx); } - // if not found, create tx to split exact output - if (splitOutputTx == null) { - if (openOffer.getSplitOutputTxHash() != null) { - log.warn("Split output tx unexpectedly unavailable for offer, offerId={}, split output tx={}", openOffer.getId(), openOffer.getSplitOutputTxHash()); - setSplitOutputTx(openOffer, null); - } - try { - splitOrSchedule(openOffers, openOffer, amountNeeded); - } catch (Exception e) { - log.warn("Unable to split or schedule funds for offer {}: {}", openOffer.getId(), e.getMessage()); - openOffer.getOffer().setState(Offer.State.INVALID); - errorMessageHandler.handleErrorMessage(e.getMessage()); - return; - } - } else if (!splitOutputTx.isLocked()) { - - // otherwise sign and post offer if split output available - signAndPostOffer(openOffer, true, resultHandler, errorMessageHandler); + // if wallet has exact available balance, try to sign and post directly + if (xmrWalletService.getAvailableBalance().equals(amountNeeded)) { + signAndPostOffer(openOffer, true, resultHandler, (errorMessage) -> { + splitOrSchedule(splitOutputTx, openOffers, openOffer, amountNeeded, resultHandler, errorMessageHandler); + }); return; + } else { + splitOrSchedule(splitOutputTx, openOffers, openOffer, amountNeeded, resultHandler, errorMessageHandler); } + } else { // sign and post offer if enough funds @@ -1017,11 +1007,10 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe return; } else if (openOffer.getScheduledTxHashes() == null) { scheduleWithEarliestTxs(openOffers, openOffer); + resultHandler.handleResult(null); + return; } } - - // handle result - resultHandler.handleResult(null); } catch (Exception e) { if (!openOffer.isCanceled()) log.error("Error processing pending offer: {}\n", e.getMessage(), e); errorMessageHandler.handleErrorMessage(e.getMessage()); @@ -1087,13 +1076,13 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe if (output.isSpent() || output.isFrozen()) removeTxs.add(tx); } } - if (!hasExactAmount(tx, reserveAmount, preferredSubaddressIndex)) removeTxs.add(tx); + if (!hasExactOutput(tx, reserveAmount, preferredSubaddressIndex)) removeTxs.add(tx); } splitOutputTxs.removeAll(removeTxs); return splitOutputTxs; } - private boolean hasExactAmount(MoneroTxWallet tx, BigInteger amount, Integer preferredSubaddressIndex) { + private boolean hasExactOutput(MoneroTxWallet tx, BigInteger amount, Integer preferredSubaddressIndex) { boolean hasExactOutput = (tx.getOutputsWallet(new MoneroOutputQuery() .setAccountIndex(0) .setSubaddressIndex(preferredSubaddressIndex) @@ -1115,7 +1104,35 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe return earliestUnscheduledTx; } - private void splitOrSchedule(List<OpenOffer> openOffers, OpenOffer openOffer, BigInteger offerReserveAmount) { + // if split tx not found and cannot reserve exact amount directly, create tx to split or reserve exact output + private void splitOrSchedule(MoneroTxWallet splitOutputTx, List<OpenOffer> openOffers, OpenOffer openOffer, BigInteger amountNeeded, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + if (splitOutputTx == null) { + if (openOffer.getSplitOutputTxHash() != null) { + log.warn("Split output tx unexpectedly unavailable for offer, offerId={}, split output tx={}", openOffer.getId(), openOffer.getSplitOutputTxHash()); + setSplitOutputTx(openOffer, null); + } + try { + splitOrScheduleAux(openOffers, openOffer, amountNeeded); + resultHandler.handleResult(null); + return; + } catch (Exception e) { + log.warn("Unable to split or schedule funds for offer {}: {}", openOffer.getId(), e.getMessage()); + openOffer.getOffer().setState(Offer.State.INVALID); + errorMessageHandler.handleErrorMessage(e.getMessage()); + return; + } + } else if (!splitOutputTx.isLocked()) { + + // otherwise sign and post offer if split output available + signAndPostOffer(openOffer, true, resultHandler, errorMessageHandler); + return; + } else { + resultHandler.handleResult(null); + return; + } + } + + private void splitOrScheduleAux(List<OpenOffer> openOffers, OpenOffer openOffer, BigInteger offerReserveAmount) { // handle sufficient available balance to split output boolean sufficientAvailableBalance = xmrWalletService.getAvailableBalance().compareTo(offerReserveAmount) >= 0; @@ -1299,13 +1316,13 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe openOffer.setScheduledAmount(null); requestPersistence(); - resultHandler.handleResult(transaction); if (!stopped) { startPeriodicRepublishOffersTimer(); startPeriodicRefreshOffersTimer(); } else { log.debug("We have stopped already. We ignore that placeOfferProtocol.placeOffer.onResult call."); } + resultHandler.handleResult(transaction); }, errorMessageHandler); 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 0d9271a41e..e873d1e561 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,6 +87,9 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> { try { //if (true) throw new RuntimeException("Pretend error"); reserveTx = model.getXmrWalletService().createReserveTx(penaltyFee, makerFee, sendAmount, securityDeposit, returnAddress, openOffer.isReserveExactAmount(), preferredSubaddressIndex); + } catch (IllegalStateException e) { + log.warn("Illegal state creating reserve tx, offerId={}, error={}", openOffer.getShortId(), i + 1, e.getMessage()); + throw e; } catch (Exception e) { log.warn("Error creating reserve tx, offerId={}, attempt={}/{}, error={}", openOffer.getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); model.getXmrWalletService().handleWalletError(e, sourceConnection); diff --git a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerSendSignOfferRequest.java b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerSendSignOfferRequest.java index 2037b51d09..3644492735 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerSendSignOfferRequest.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerSendSignOfferRequest.java @@ -77,7 +77,7 @@ public class MakerSendSignOfferRequest extends Task<PlaceOfferModel> { offer.getOfferPayload().getReserveTxKeyImages(), returnAddress); - // send request to least used arbitrators until success + // send request to random arbitrators until success sendSignOfferRequests(request, () -> { complete(); }, (errorMessage) -> { diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java index e6c71032f4..aa0fc9dfe9 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java @@ -70,6 +70,9 @@ public class TakerReserveTradeFunds extends TradeTask { MoneroRpcConnection sourceConnection = trade.getXmrConnectionService().getConnection(); try { reserveTx = model.getXmrWalletService().createReserveTx(penaltyFee, takerFee, sendAmount, securityDeposit, returnAddress, false, null); + } catch (IllegalStateException e) { + log.warn("Illegal state creating reserve tx, offerId={}, error={}", trade.getShortId(), i + 1, e.getMessage()); + throw e; } catch (Exception e) { log.warn("Error creating reserve tx, tradeId={}, attempt={}/{}, error={}", trade.getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); trade.getXmrWalletService().handleWalletError(e, sourceConnection); From 251a973fd6296912e8109d16805991265c35a326 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Sun, 9 Mar 2025 09:44:20 -0400 Subject: [PATCH 11/21] do not refresh or republish offers if disconnected from xmr node --- .../haveno/core/offer/OpenOfferManager.java | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java index a475691736..b4b8dd80fb 100644 --- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java +++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java @@ -1978,6 +1978,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } private boolean preventedFromPublishing(OpenOffer openOffer) { + if (!Boolean.TRUE.equals(xmrConnectionService.isConnected())) return true; return openOffer.isDeactivated() || openOffer.isCanceled() || openOffer.getOffer().getOfferPayload().getArbitratorSigner() == null; } @@ -2000,25 +2001,27 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe if (periodicRefreshOffersTimer == null) periodicRefreshOffersTimer = UserThread.runPeriodically(() -> { if (!stopped) { - int size = openOffers.size(); - //we clone our list as openOffers might change during our delayed call - final ArrayList<OpenOffer> openOffersList = new ArrayList<>(openOffers.getList()); - for (int i = 0; i < size; i++) { - // we delay to avoid reaching throttle limits - // roughly 4 offers per second - - long delay = 300; - final long minDelay = (i + 1) * delay; - final long maxDelay = (i + 2) * delay; - final OpenOffer openOffer = openOffersList.get(i); - UserThread.runAfterRandomDelay(() -> { - // we need to check if in the meantime the offer has been removed - boolean contained = false; - synchronized (openOffers) { - contained = openOffers.contains(openOffer); - } - if (contained) maybeRefreshOffer(openOffer, 0, 1); - }, minDelay, maxDelay, TimeUnit.MILLISECONDS); + synchronized (openOffers) { + int size = openOffers.size(); + //we clone our list as openOffers might change during our delayed call + final ArrayList<OpenOffer> openOffersList = new ArrayList<>(openOffers.getList()); + for (int i = 0; i < size; i++) { + // we delay to avoid reaching throttle limits + // roughly 4 offers per second + + long delay = 300; + final long minDelay = (i + 1) * delay; + final long maxDelay = (i + 2) * delay; + final OpenOffer openOffer = openOffersList.get(i); + UserThread.runAfterRandomDelay(() -> { + // we need to check if in the meantime the offer has been removed + boolean contained = false; + synchronized (openOffers) { + contained = openOffers.contains(openOffer); + } + if (contained) maybeRefreshOffer(openOffer, 0, 1); + }, minDelay, maxDelay, TimeUnit.MILLISECONDS); + } } } else { log.debug("We have stopped already. We ignore that periodicRefreshOffersTimer.run call."); From 00a2a7c2b7981310f657cc8dad4edc7456339690 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Sun, 9 Mar 2025 09:50:20 -0400 Subject: [PATCH 12/21] nack offer availability request if disconnected from xmr node --- .../src/main/java/haveno/core/offer/OpenOfferManager.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java index b4b8dd80fb..32a1507f77 100644 --- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java +++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java @@ -1574,6 +1574,14 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe return; } + // Don't allow trade start if not connected to Monero node + if (!Boolean.TRUE.equals(xmrConnectionService.isConnected())) { + errorMessage = "We got a handleOfferAvailabilityRequest but we are not connected to a Monero node."; + log.info(errorMessage); + sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); + return; + } + if (stopped) { errorMessage = "We have stopped already. We ignore that handleOfferAvailabilityRequest call."; log.debug(errorMessage); From 84d8a17ab492d5c173a2e5bf4fc6bdc23e226f37 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Mon, 3 Mar 2025 06:56:20 -0500 Subject: [PATCH 13/21] rename payment sent message state property for seller --- .../main/java/haveno/core/trade/Trade.java | 8 +++--- .../core/trade/protocol/ProcessModel.java | 26 ++++++++++++------- .../core/trade/protocol/TradeProtocol.java | 3 ++- .../tasks/BuyerSendPaymentSentMessage.java | 6 ++--- ...yerSendPaymentSentMessageToArbitrator.java | 3 +-- .../BuyerSendPaymentSentMessageToSeller.java | 10 +++---- .../pendingtrades/PendingTradesViewModel.java | 10 +++---- .../steps/buyer/BuyerStep3View.java | 6 ++--- proto/src/main/proto/pb.proto | 2 +- 9 files changed, 41 insertions(+), 33 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index 0bc6105049..6ae5c9fcc4 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -735,9 +735,9 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { // TODO: buyer's payment sent message state property became unsynced if shut down while awaiting ack from seller. fixed in v1.0.19 so this check can be removed? if (isBuyer()) { MessageState expectedState = getPaymentSentMessageState(); - if (expectedState != null && expectedState != processModel.getPaymentSentMessageStateProperty().get()) { - log.warn("Updating unexpected payment sent message state for {} {}, expected={}, actual={}", getClass().getSimpleName(), getId(), expectedState, processModel.getPaymentSentMessageStateProperty().get()); - processModel.getPaymentSentMessageStateProperty().set(expectedState); + if (expectedState != null && expectedState != processModel.getPaymentSentMessageStatePropertySeller().get()) { + log.warn("Updating unexpected payment sent message state for {} {}, expected={}, actual={}", getClass().getSimpleName(), getId(), expectedState, processModel.getPaymentSentMessageStatePropertySeller().get()); + processModel.getPaymentSentMessageStatePropertySeller().set(expectedState); } } @@ -2022,7 +2022,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { public MessageState getPaymentSentMessageState() { if (isPaymentReceived()) return MessageState.ACKNOWLEDGED; - if (processModel.getPaymentSentMessageStateProperty().get() == MessageState.ACKNOWLEDGED) return MessageState.ACKNOWLEDGED; + if (processModel.getPaymentSentMessageStatePropertySeller().get() == MessageState.ACKNOWLEDGED) return MessageState.ACKNOWLEDGED; switch (state) { case BUYER_SENT_PAYMENT_SENT_MSG: return MessageState.SENT; diff --git a/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java b/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java index 54aaa65d37..d81c4f476a 100644 --- a/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java +++ b/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java @@ -163,7 +163,7 @@ public class ProcessModel implements Model, PersistablePayload { // PaymentSentMessage. As well we do an automatic re-send in case it was not ACKed yet. // To enable that even after restart we persist the state. @Setter - private ObjectProperty<MessageState> paymentSentMessageStateProperty = new SimpleObjectProperty<>(MessageState.UNDEFINED); + private ObjectProperty<MessageState> paymentSentMessageStatePropertySeller = new SimpleObjectProperty<>(MessageState.UNDEFINED); @Setter private ObjectProperty<MessageState> paymentSentMessageStatePropertyArbitrator = new SimpleObjectProperty<>(MessageState.UNDEFINED); private ObjectProperty<Boolean> paymentAccountDecryptedProperty = new SimpleObjectProperty<>(false); @@ -203,7 +203,7 @@ public class ProcessModel implements Model, PersistablePayload { .setPubKeyRing(pubKeyRing.toProtoMessage()) .setUseSavingsWallet(useSavingsWallet) .setFundsNeededForTrade(fundsNeededForTrade) - .setPaymentSentMessageState(paymentSentMessageStateProperty.get().name()) + .setPaymentSentMessageStateSeller(paymentSentMessageStatePropertySeller.get().name()) .setPaymentSentMessageStateArbitrator(paymentSentMessageStatePropertyArbitrator.get().name()) .setBuyerPayoutAmountFromMediation(buyerPayoutAmountFromMediation) .setSellerPayoutAmountFromMediation(sellerPayoutAmountFromMediation) @@ -240,9 +240,9 @@ public class ProcessModel implements Model, PersistablePayload { processModel.setTradeFeeAddress(ProtoUtil.stringOrNullFromProto(proto.getTradeFeeAddress())); processModel.setMultisigAddress(ProtoUtil.stringOrNullFromProto(proto.getMultisigAddress())); - String paymentSentMessageStateString = ProtoUtil.stringOrNullFromProto(proto.getPaymentSentMessageState()); - MessageState paymentSentMessageState = ProtoUtil.enumFromProto(MessageState.class, paymentSentMessageStateString); - processModel.setPaymentSentMessageState(paymentSentMessageState); + String paymentSentMessageStateSellerString = ProtoUtil.stringOrNullFromProto(proto.getPaymentSentMessageStateSeller()); + MessageState paymentSentMessageStateSeller = ProtoUtil.enumFromProto(MessageState.class, paymentSentMessageStateSellerString); + processModel.setPaymentSentMessageStateSeller(paymentSentMessageStateSeller); String paymentSentMessageStateArbitratorString = ProtoUtil.stringOrNullFromProto(proto.getPaymentSentMessageStateArbitrator()); MessageState paymentSentMessageStateArbitrator = ProtoUtil.enumFromProto(MessageState.class, paymentSentMessageStateArbitratorString); @@ -274,11 +274,11 @@ public class ProcessModel implements Model, PersistablePayload { return getP2PService().getAddress(); } - void setPaymentSentAckMessage(AckMessage ackMessage) { + void setPaymentSentAckMessageSeller(AckMessage ackMessage) { MessageState messageState = ackMessage.isSuccess() ? MessageState.ACKNOWLEDGED : MessageState.FAILED; - setPaymentSentMessageState(messageState); + setPaymentSentMessageStateSeller(messageState); } void setPaymentSentAckMessageArbitrator(AckMessage ackMessage) { @@ -288,8 +288,8 @@ public class ProcessModel implements Model, PersistablePayload { setPaymentSentMessageStateArbitrator(messageState); } - public void setPaymentSentMessageState(MessageState paymentSentMessageStateProperty) { - this.paymentSentMessageStateProperty.set(paymentSentMessageStateProperty); + public void setPaymentSentMessageStateSeller(MessageState paymentSentMessageStateProperty) { + this.paymentSentMessageStatePropertySeller.set(paymentSentMessageStateProperty); if (tradeManager != null) { tradeManager.requestPersistence(); } @@ -302,6 +302,14 @@ public class ProcessModel implements Model, PersistablePayload { } } + public boolean isPaymentSentMessageAckedBySeller() { + return paymentSentMessageStatePropertySeller.get() == MessageState.ACKNOWLEDGED; + } + + public boolean isPaymentSentMessageAckedByArbitrator() { + return paymentSentMessageStatePropertyArbitrator.get() == MessageState.ACKNOWLEDGED; + } + void setDepositTxSentAckMessage(AckMessage ackMessage) { MessageState messageState = ackMessage.isSuccess() ? MessageState.ACKNOWLEDGED : diff --git a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java index 684dfb7c62..6a158bea7a 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java @@ -652,11 +652,12 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D // handle ack for PaymentSentMessage, which automatically re-sends if not ACKed in a certain time if (ackMessage.getSourceMsgClassName().equals(PaymentSentMessage.class.getSimpleName())) { if (trade.getTradePeer(sender) == trade.getSeller()) { - processModel.setPaymentSentAckMessage(ackMessage); + processModel.setPaymentSentAckMessageSeller(ackMessage); trade.setStateIfValidTransitionTo(Trade.State.SELLER_RECEIVED_PAYMENT_SENT_MSG); processModel.getTradeManager().requestPersistence(); } else if (trade.getTradePeer(sender) == trade.getArbitrator()) { processModel.setPaymentSentAckMessageArbitrator(ackMessage); + processModel.getTradeManager().requestPersistence(); } else if (!ackMessage.isSuccess()) { String err = "Received AckMessage with error state for " + ackMessage.getSourceMsgClassName() + " from "+ sender + " with tradeId " + trade.getId() + " and errorMessage=" + ackMessage.getErrorMessage(); log.warn(err); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java index f060effe78..bc064399a3 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java @@ -170,7 +170,7 @@ public abstract class BuyerSendPaymentSentMessage extends SendMailboxMessageTask timer.stop(); } if (listener != null) { - processModel.getPaymentSentMessageStateProperty().removeListener(listener); + processModel.getPaymentSentMessageStatePropertySeller().removeListener(listener); } } @@ -194,8 +194,8 @@ public abstract class BuyerSendPaymentSentMessage extends SendMailboxMessageTask if (resendCounter == 0) { listener = (observable, oldValue, newValue) -> onMessageStateChange(newValue); - processModel.getPaymentSentMessageStateProperty().addListener(listener); - onMessageStateChange(processModel.getPaymentSentMessageStateProperty().get()); + processModel.getPaymentSentMessageStatePropertySeller().addListener(listener); + onMessageStateChange(processModel.getPaymentSentMessageStatePropertySeller().get()); } // first re-send is after 2 minutes, then increase the delay exponentially diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToArbitrator.java b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToArbitrator.java index cc4113e342..cd3098737a 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToArbitrator.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToArbitrator.java @@ -18,7 +18,6 @@ package haveno.core.trade.protocol.tasks; import haveno.common.taskrunner.TaskRunner; -import haveno.core.network.MessageState; import haveno.core.trade.Trade; import haveno.core.trade.protocol.TradePeer; import lombok.EqualsAndHashCode; @@ -59,6 +58,6 @@ public class BuyerSendPaymentSentMessageToArbitrator extends BuyerSendPaymentSen @Override protected boolean isAckedByReceiver() { - return trade.getProcessModel().getPaymentSentMessageStatePropertyArbitrator().get() == MessageState.ACKNOWLEDGED; + return trade.getProcessModel().isPaymentSentMessageAckedByArbitrator(); } } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToSeller.java b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToSeller.java index caf402be0a..825220d5b4 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToSeller.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToSeller.java @@ -40,25 +40,25 @@ public class BuyerSendPaymentSentMessageToSeller extends BuyerSendPaymentSentMes @Override protected void setStateSent() { - trade.getProcessModel().setPaymentSentMessageState(MessageState.SENT); + trade.getProcessModel().setPaymentSentMessageStateSeller(MessageState.SENT); super.setStateSent(); } @Override protected void setStateArrived() { - trade.getProcessModel().setPaymentSentMessageState(MessageState.ARRIVED); + trade.getProcessModel().setPaymentSentMessageStateSeller(MessageState.ARRIVED); super.setStateArrived(); } @Override protected void setStateStoredInMailbox() { - trade.getProcessModel().setPaymentSentMessageState(MessageState.STORED_IN_MAILBOX); + trade.getProcessModel().setPaymentSentMessageStateSeller(MessageState.STORED_IN_MAILBOX); super.setStateStoredInMailbox(); } @Override protected void setStateFault() { - trade.getProcessModel().setPaymentSentMessageState(MessageState.FAILED); + trade.getProcessModel().setPaymentSentMessageStateSeller(MessageState.FAILED); super.setStateFault(); } @@ -72,6 +72,6 @@ public class BuyerSendPaymentSentMessageToSeller extends BuyerSendPaymentSentMes @Override protected boolean isAckedByReceiver() { - return trade.getState().ordinal() >= Trade.State.SELLER_RECEIVED_PAYMENT_SENT_MSG.ordinal(); + return trade.getProcessModel().isPaymentSentMessageAckedBySeller(); } } diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java index 41881c58be..b9936236c6 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java @@ -100,7 +100,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad private final ObjectProperty<BuyerState> buyerState = new SimpleObjectProperty<>(); private final ObjectProperty<SellerState> sellerState = new SimpleObjectProperty<>(); @Getter - private final ObjectProperty<MessageState> messageStateProperty = new SimpleObjectProperty<>(MessageState.UNDEFINED); + private final ObjectProperty<MessageState> paymentSentMessageStateProperty = new SimpleObjectProperty<>(MessageState.UNDEFINED); private Subscription tradeStateSubscription; private Subscription paymentAccountDecryptedSubscription; private Subscription payoutStateSubscription; @@ -186,7 +186,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad if (messageStateSubscription != null) { messageStateSubscription.unsubscribe(); - messageStateProperty.set(MessageState.UNDEFINED); + paymentSentMessageStateProperty.set(MessageState.UNDEFINED); } if (selectedItem != null) { @@ -200,7 +200,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad payoutStateSubscription = EasyBind.subscribe(trade.payoutStateProperty(), state -> { onPayoutStateChanged(state); }); - messageStateSubscription = EasyBind.subscribe(trade.getProcessModel().getPaymentSentMessageStateProperty(), this::onMessageStateChanged); + messageStateSubscription = EasyBind.subscribe(trade.getProcessModel().getPaymentSentMessageStatePropertySeller(), this::onPaymentSentMessageStateChanged); } } } @@ -215,8 +215,8 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad }); } - private void onMessageStateChanged(MessageState messageState) { - messageStateProperty.set(messageState); + private void onPaymentSentMessageStateChanged(MessageState messageState) { + paymentSentMessageStateProperty.set(messageState); } /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java index 57fda229f3..b28eda4a10 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java @@ -52,7 +52,7 @@ public class BuyerStep3View extends TradeStepView { public void activate() { super.activate(); - model.getMessageStateProperty().addListener(messageStateChangeListener); + model.getPaymentSentMessageStateProperty().addListener(messageStateChangeListener); updateMessageStateInfo(); } @@ -60,7 +60,7 @@ public class BuyerStep3View extends TradeStepView { public void deactivate() { super.deactivate(); - model.getMessageStateProperty().removeListener(messageStateChangeListener); + model.getPaymentSentMessageStateProperty().removeListener(messageStateChangeListener); } @@ -87,7 +87,7 @@ public class BuyerStep3View extends TradeStepView { } private void updateMessageStateInfo() { - MessageState messageState = model.getMessageStateProperty().get(); + MessageState messageState = model.getPaymentSentMessageStateProperty().get(); textFieldWithIcon.setText(Res.get("message.state." + messageState.name())); Label iconLabel = textFieldWithIcon.getIconLabel(); switch (messageState) { diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index 04c32ee8dc..6436052333 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -1568,7 +1568,7 @@ message ProcessModel { bytes payout_tx_signature = 4; bool use_savings_wallet = 5; int64 funds_needed_for_trade = 6; - string payment_sent_message_state = 7; + string payment_sent_message_state_seller = 7; string payment_sent_message_state_arbitrator = 8; bytes maker_signature = 9; TradePeer maker = 10; From 38c0855728b08c36bb7846d834bb53f3b2e315aa Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Mon, 3 Mar 2025 07:55:57 -0500 Subject: [PATCH 14/21] save payment received message immediately for reprocessing --- .../haveno/core/trade/protocol/TradeProtocol.java | 13 +++++++++++++ .../tasks/ProcessPaymentReceivedMessage.java | 3 --- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java index 6a158bea7a..117c16cc05 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java @@ -536,6 +536,19 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D private void handle(PaymentReceivedMessage message, NodeAddress peer, boolean reprocessOnError) { System.out.println(getClass().getSimpleName() + ".handle(PaymentReceivedMessage) for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + + // validate signature + try { + HavenoUtils.verifyPaymentReceivedMessage(trade, message); + } catch (Throwable t) { + log.warn("Ignoring PaymentReceivedMessage with invalid signature for {} {}, error={}", trade.getClass().getSimpleName(), trade.getId(), t.getMessage()); + return; + } + + // save message for reprocessing + trade.getSeller().setPaymentReceivedMessage(message); + trade.requestPersistence(); + if (!trade.isInitialized() || trade.isShutDown()) return; ThreadUtils.execute(() -> { if (!(trade instanceof BuyerTrade || trade instanceof ArbitratorTrade)) { diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentReceivedMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentReceivedMessage.java index 2ce29828a4..f1016f3c61 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentReceivedMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentReceivedMessage.java @@ -80,9 +80,6 @@ public class ProcessPaymentReceivedMessage extends TradeTask { return; } - // save message for reprocessing - trade.getSeller().setPaymentReceivedMessage(message); - // set state trade.getSeller().setUpdatedMultisigHex(message.getUpdatedMultisigHex()); trade.getBuyer().setAccountAgeWitness(message.getBuyerAccountAgeWitness()); From fb2b4a0c6ab20a4d8d451d0e7b6e2d641458c9c5 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Mon, 3 Mar 2025 08:51:32 -0500 Subject: [PATCH 15/21] save and reprocess payment sent message --- .../main/java/haveno/core/trade/Trade.java | 5 +- .../core/trade/protocol/TradeProtocol.java | 49 ++++++++++++++++++- .../tasks/ProcessPaymentSentMessage.java | 1 - 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index 6ae5c9fcc4..dc3a1bc7a2 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -2441,8 +2441,9 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { if (!wasWalletSynced) trySyncWallet(true); updatePollPeriod(); - // reprocess pending payout messages - this.getProtocol().maybeReprocessPaymentReceivedMessage(false); + // reprocess pending messages + getProtocol().maybeReprocessPaymentSentMessage(false); + getProtocol().maybeReprocessPaymentReceivedMessage(false); HavenoUtils.arbitrationManager.maybeReprocessDisputeClosedMessage(this, false); startPolling(); diff --git a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java index 117c16cc05..6400e69f6a 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java @@ -106,6 +106,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D protected ErrorMessageHandler errorMessageHandler; private boolean depositsConfirmedTasksCalled; + private int reprocessPaymentSentMessageCount; private int reprocessPaymentReceivedMessageCount; /////////////////////////////////////////////////////////////////////////////////////////// @@ -279,6 +280,22 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D }, trade.getId()); } + public void maybeReprocessPaymentSentMessage(boolean reprocessOnError) { + if (trade.isShutDownStarted()) return; + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { + + // skip if no need to reprocess + if (trade.isBuyer() || trade.getBuyer().getPaymentSentMessage() == null || trade.getState().ordinal() >= Trade.State.BUYER_SENT_PAYMENT_SENT_MSG.ordinal()) { + return; + } + + log.warn("Reprocessing payment sent message for {} {}", trade.getClass().getSimpleName(), trade.getId()); + handle(trade.getBuyer().getPaymentSentMessage(), trade.getBuyer().getPaymentSentMessage().getSenderNodeAddress(), reprocessOnError); + } + }, trade.getId()); + } + public void maybeReprocessPaymentReceivedMessage(boolean reprocessOnError) { if (trade.isShutDownStarted()) return; ThreadUtils.execute(() -> { @@ -481,7 +498,25 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D // received by seller and arbitrator protected void handle(PaymentSentMessage message, NodeAddress peer) { + handle(message, peer, true); + } + + // received by seller and arbitrator + protected void handle(PaymentSentMessage message, NodeAddress peer, boolean reprocessOnError) { System.out.println(getClass().getSimpleName() + ".handle(PaymentSentMessage) for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + + // validate signature + try { + HavenoUtils.verifyPaymentSentMessage(trade, message); + } catch (Throwable t) { + log.warn("Ignoring PaymentSentMessage with invalid signature for {} {}, error={}", trade.getClass().getSimpleName(), trade.getId(), t.getMessage()); + return; + } + + // save message for reprocessing + trade.getBuyer().setPaymentSentMessage(message); + trade.requestPersistence(); + if (!trade.isInitialized() || trade.isShutDown()) return; if (!(trade instanceof SellerTrade || trade instanceof ArbitratorTrade)) { log.warn("Ignoring PaymentSentMessage since not seller or arbitrator"); @@ -521,7 +556,19 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D handleTaskRunnerSuccess(peer, message); }, (errorMessage) -> { - handleTaskRunnerFault(peer, message, errorMessage); + log.warn("Error processing payment sent message: " + errorMessage); + processModel.getTradeManager().requestPersistence(); + + // schedule to reprocess message unless deleted + if (trade.getBuyer().getPaymentSentMessage() != null) { + UserThread.runAfter(() -> { + reprocessPaymentSentMessageCount++; + maybeReprocessPaymentSentMessage(reprocessOnError); + }, trade.getReprocessDelayInSeconds(reprocessPaymentSentMessageCount)); + } else { + handleTaskRunnerFault(peer, message, errorMessage); // otherwise send nack + } + unlatchTrade(); }))) .executeTasks(true); awaitTradeLatch(); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentSentMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentSentMessage.java index 93d1ce520a..de7d949ade 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentSentMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentSentMessage.java @@ -48,7 +48,6 @@ public class ProcessPaymentSentMessage extends TradeTask { trade.getBuyer().setNodeAddress(processModel.getTempTradePeerNodeAddress()); // update state from message - trade.getBuyer().setPaymentSentMessage(message); trade.getBuyer().setUpdatedMultisigHex(message.getUpdatedMultisigHex()); trade.getSeller().setAccountAgeWitness(message.getSellerAccountAgeWitness()); String counterCurrencyTxId = message.getCounterCurrencyTxId(); From 1510e6f18d49ef9ff6610b9b6f550b12300ee228 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Mon, 3 Mar 2025 17:27:50 -0500 Subject: [PATCH 16/21] logging cleanup --- core/src/main/java/haveno/core/trade/Trade.java | 2 +- core/src/main/java/haveno/core/trade/TradeManager.java | 4 ++-- .../java/haveno/core/xmr/setup/MoneroWalletRpcManager.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index dc3a1bc7a2..9466355f34 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -1089,10 +1089,10 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { } catch (IllegalArgumentException | IllegalStateException e) { throw e; } catch (Exception e) { + log.warn("Failed to import multisig hex, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); handleWalletError(e, sourceConnection); doPollWallet(); if (isPayoutPublished()) break; - log.warn("Failed to import multisig hex, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying } diff --git a/core/src/main/java/haveno/core/trade/TradeManager.java b/core/src/main/java/haveno/core/trade/TradeManager.java index 88db590c42..c98978ae4c 100644 --- a/core/src/main/java/haveno/core/trade/TradeManager.java +++ b/core/src/main/java/haveno/core/trade/TradeManager.java @@ -747,7 +747,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } private void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) { - log.info("TradeManager handling InitMultisigRequest for tradeId={}, sender={}, uid={}", request.getOfferId(), sender, request.getUid()); + log.info("TradeManager handling InitMultisigRequest for tradeId={}, sender={}, uid={}", request.getOfferId(), sender, request.getUid()); try { Validator.nonEmptyStringOf(request.getOfferId()); @@ -766,7 +766,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } private void handleSignContractRequest(SignContractRequest request, NodeAddress sender) { - log.info("TradeManager handling SignContractRequest for tradeId={}, sender={}, uid={}", request.getOfferId(), sender, request.getUid()); + log.info("TradeManager handling SignContractRequest for tradeId={}, sender={}, uid={}", request.getOfferId(), sender, request.getUid()); try { Validator.nonEmptyStringOf(request.getOfferId()); diff --git a/core/src/main/java/haveno/core/xmr/setup/MoneroWalletRpcManager.java b/core/src/main/java/haveno/core/xmr/setup/MoneroWalletRpcManager.java index c993ebd181..1bb1e3500e 100644 --- a/core/src/main/java/haveno/core/xmr/setup/MoneroWalletRpcManager.java +++ b/core/src/main/java/haveno/core/xmr/setup/MoneroWalletRpcManager.java @@ -135,7 +135,7 @@ public class MoneroWalletRpcManager { // stop process String pid = walletRpc.getProcess() == null ? null : String.valueOf(walletRpc.getProcess().pid()); - log.info("Stopping MoneroWalletRpc path={}, port={}, pid={}", path, port, pid); + log.info("Stopping MoneroWalletRpc path={}, port={}, pid={}, force={}", path, port, pid, force); walletRpc.stopProcess(force); } From a55daf803efca28662af7aaebdbe26fd28d64632 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Tue, 4 Mar 2025 10:23:25 -0500 Subject: [PATCH 17/21] call trade message handling off trade thread --- .../main/java/haveno/core/trade/protocol/TradeProtocol.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java index 6400e69f6a..caeb654813 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java @@ -125,12 +125,12 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D protected void onTradeMessage(TradeMessage message, NodeAddress peerNodeAddress) { log.info("Received {} as TradeMessage from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peerNodeAddress, message.getOfferId(), message.getUid()); - ThreadUtils.execute(() -> handle(message, peerNodeAddress), trade.getId()); + handle(message, peerNodeAddress); } protected void onMailboxMessage(TradeMessage message, NodeAddress peerNodeAddress) { log.info("Received {} as MailboxMessage from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peerNodeAddress, message.getOfferId(), message.getUid()); - ThreadUtils.execute(() -> handle(message, peerNodeAddress), trade.getId()); + handle(message, peerNodeAddress); } private void handle(TradeMessage message, NodeAddress peerNodeAddress) { From 46734459d497ce2b2c9190897c78e2d146719711 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Tue, 4 Mar 2025 06:57:41 -0500 Subject: [PATCH 18/21] highlight logs for handling trade protocol messages --- .../core/trade/protocol/ArbitratorProtocol.java | 4 ++-- .../haveno/core/trade/protocol/BuyerProtocol.java | 2 +- .../core/trade/protocol/SellerProtocol.java | 2 +- .../haveno/core/trade/protocol/TradeProtocol.java | 15 ++++++++------- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java b/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java index 98b3f1ab0d..b25c6c68d1 100644 --- a/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java @@ -43,7 +43,7 @@ public class ArbitratorProtocol extends DisputeProtocol { /////////////////////////////////////////////////////////////////////////////////////////// public void handleInitTradeRequest(InitTradeRequest message, NodeAddress peer, ErrorMessageHandler errorMessageHandler) { - System.out.println("ArbitratorProtocol.handleInitTradeRequest()"); + log.info(TradeProtocol.LOG_HIGHLIGHT + "handleInitTradeRequest() for {} {}", trade.getClass().getSimpleName(), trade.getShortId()); ThreadUtils.execute(() -> { synchronized (trade.getLock()) { latchTrade(); @@ -78,7 +78,7 @@ public class ArbitratorProtocol extends DisputeProtocol { } public void handleDepositRequest(DepositRequest request, NodeAddress sender) { - System.out.println("ArbitratorProtocol.handleDepositRequest() " + trade.getId()); + log.info(TradeProtocol.LOG_HIGHLIGHT + "handleDepositRequest() for {} {}", trade.getClass().getSimpleName(), trade.getShortId()); ThreadUtils.execute(() -> { synchronized (trade.getLock()) { latchTrade(); diff --git a/core/src/main/java/haveno/core/trade/protocol/BuyerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/BuyerProtocol.java index 06e1eead7c..4302f6db6f 100644 --- a/core/src/main/java/haveno/core/trade/protocol/BuyerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/BuyerProtocol.java @@ -119,7 +119,7 @@ public class BuyerProtocol extends DisputeProtocol { /////////////////////////////////////////////////////////////////////////////////////////// public void onPaymentSent(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { - System.out.println("BuyerProtocol.onPaymentSent()"); + log.info(TradeProtocol.LOG_HIGHLIGHT + "BuyerProtocol.onPaymentSent() for {} {}", trade.getClass().getSimpleName(), trade.getShortId()); ThreadUtils.execute(() -> { synchronized (trade.getLock()) { latchTrade(); diff --git a/core/src/main/java/haveno/core/trade/protocol/SellerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/SellerProtocol.java index 4de8fa0d6a..2b7f45877a 100644 --- a/core/src/main/java/haveno/core/trade/protocol/SellerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/SellerProtocol.java @@ -115,7 +115,7 @@ public class SellerProtocol extends DisputeProtocol { /////////////////////////////////////////////////////////////////////////////////////////// public void onPaymentReceived(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { - log.info("SellerProtocol.onPaymentReceived()"); + log.info(TradeProtocol.LOG_HIGHLIGHT + "SellerProtocol.onPaymentReceived() for {} {}", trade.getClass().getSimpleName(), trade.getShortId()); ThreadUtils.execute(() -> { synchronized (trade.getLock()) { latchTrade(); diff --git a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java index caeb654813..08c99570f6 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java @@ -96,6 +96,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D private static final String TIMEOUT_REACHED = "Timeout reached."; public static final int MAX_ATTEMPTS = 5; // max attempts to create txs and other wallet functions public static final long REPROCESS_DELAY_MS = 5000; + public static final String LOG_HIGHLIGHT = "\u001B[0m"; // terminal default protected final ProcessModel processModel; protected final Trade trade; @@ -313,7 +314,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D } public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) { - System.out.println(getClass().getSimpleName() + ".handleInitMultisigRequest() for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + log.info(LOG_HIGHLIGHT + "handleInitMultisigRequest() for " + trade.getClass().getSimpleName() + " " + trade.getShortId() + " from " + sender); trade.addInitProgressStep(); ThreadUtils.execute(() -> { synchronized (trade.getLock()) { @@ -350,7 +351,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D } public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) { - System.out.println(getClass().getSimpleName() + ".handleSignContractRequest() for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + log.info(LOG_HIGHLIGHT + "handleSignContractRequest() for " + trade.getClass().getSimpleName() + " " + trade.getShortId() + " from " + sender); ThreadUtils.execute(() -> { synchronized (trade.getLock()) { @@ -393,7 +394,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D } public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) { - System.out.println(getClass().getSimpleName() + ".handleSignContractResponse() for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + log.info(LOG_HIGHLIGHT + "handleSignContractResponse() for " + trade.getClass().getSimpleName() + " " + trade.getShortId() + " from " + sender); trade.addInitProgressStep(); ThreadUtils.execute(() -> { synchronized (trade.getLock()) { @@ -439,7 +440,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D } public void handleDepositResponse(DepositResponse response, NodeAddress sender) { - System.out.println(getClass().getSimpleName() + ".handleDepositResponse() for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + log.info(LOG_HIGHLIGHT + "handleDepositResponse() for " + trade.getClass().getSimpleName() + " " + trade.getShortId() + " from " + sender); trade.addInitProgressStep(); ThreadUtils.execute(() -> { synchronized (trade.getLock()) { @@ -469,7 +470,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D } public void handle(DepositsConfirmedMessage message, NodeAddress sender) { - System.out.println(getClass().getSimpleName() + ".handle(DepositsConfirmedMessage) from " + sender + " for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + log.info(LOG_HIGHLIGHT + "handle(DepositsConfirmedMessage) for " + trade.getClass().getSimpleName() + " " + trade.getShortId() + " from " + sender); if (!trade.isInitialized() || trade.isShutDown()) return; ThreadUtils.execute(() -> { synchronized (trade.getLock()) { @@ -503,7 +504,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D // received by seller and arbitrator protected void handle(PaymentSentMessage message, NodeAddress peer, boolean reprocessOnError) { - System.out.println(getClass().getSimpleName() + ".handle(PaymentSentMessage) for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + log.info(LOG_HIGHLIGHT + "handle(PaymentSentMessage) for " + trade.getClass().getSimpleName() + " " + trade.getShortId() + " from " + peer); // validate signature try { @@ -582,7 +583,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D } private void handle(PaymentReceivedMessage message, NodeAddress peer, boolean reprocessOnError) { - System.out.println(getClass().getSimpleName() + ".handle(PaymentReceivedMessage) for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + log.info(LOG_HIGHLIGHT + "handle(PaymentReceivedMessage) for " + trade.getClass().getSimpleName() + " " + trade.getShortId() + " from " + peer); // validate signature try { From cb69d0646883490b75ae01060e1c6aca23b0ed30 Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Tue, 4 Mar 2025 15:12:57 -0500 Subject: [PATCH 19/21] increase grpc rate limits for testnet --- .../java/haveno/daemon/grpc/GrpcOffersService.java | 2 +- .../java/haveno/daemon/grpc/GrpcTradesService.java | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcOffersService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcOffersService.java index 84443da4d5..485ff38ca8 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcOffersService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcOffersService.java @@ -208,7 +208,7 @@ class GrpcOffersService extends OffersImplBase { put(getGetOffersMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 3, SECONDS)); put(getGetMyOffersMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); put(getPostOfferMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); - put(getCancelOfferMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); + put(getCancelOfferMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); }} ))); } diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcTradesService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcTradesService.java index 286fccf51a..0a5d2d39d2 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcTradesService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcTradesService.java @@ -252,14 +252,14 @@ class GrpcTradesService extends TradesImplBase { .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( new HashMap<>() {{ put(getGetTradeMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 1, SECONDS)); - put(getGetTradesMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 1, SECONDS)); - put(getTakeOfferMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 20 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); - put(getConfirmPaymentSentMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); - put(getConfirmPaymentReceivedMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); - put(getCompleteTradeMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); + put(getGetTradesMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 1, SECONDS)); + put(getTakeOfferMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); + put(getConfirmPaymentSentMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); + put(getConfirmPaymentReceivedMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); + put(getCompleteTradeMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); put(getWithdrawFundsMethod().getFullMethodName(), new GrpcCallRateMeter(3, MINUTES)); - put(getGetChatMessagesMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 4, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); - put(getSendChatMessageMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 4, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); + put(getGetChatMessagesMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 4, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); + put(getSendChatMessageMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 4, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); }} ))); } From d4eb30bb979c855f71ad9e408ecf14c2b274c9df Mon Sep 17 00:00:00 2001 From: woodser <13068859+woodser@users.noreply.github.com> Date: Tue, 4 Mar 2025 17:20:58 -0500 Subject: [PATCH 20/21] schedule import multisig hex on deposit confirmation msg --- .../main/java/haveno/core/trade/Trade.java | 41 ++++++++++++++++--- .../core/trade/protocol/ProcessModel.java | 7 +++- .../ProcessDepositsConfirmedMessage.java | 13 +----- proto/src/main/proto/pb.proto | 1 + 4 files changed, 43 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index 9466355f34..13594cc3a1 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -143,6 +143,7 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { private static final long DELETE_AFTER_NUM_BLOCKS = 2; // if deposit requested but not published private static final long EXTENDED_RPC_TIMEOUT = 600000; // 10 minutes private static final long DELETE_AFTER_MS = TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS; + private static final int NUM_CONFIRMATIONS_FOR_SCHEDULED_IMPORT = 10; protected final Object pollLock = new Object(); protected static final Object importMultisigLock = new Object(); private boolean pollInProgress; @@ -741,6 +742,11 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { } } + // handle confirmations + walletHeight.addListener((observable, oldValue, newValue) -> { + importMultisigHexIfScheduled(); + }); + // trade is initialized isInitialized = true; @@ -1077,6 +1083,26 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { } } + public void scheduleImportMultisigHex() { + processModel.setImportMultisigHexScheduled(true); + requestPersistence(); + } + + private void importMultisigHexIfScheduled() { + if (!isInitialized || isShutDownStarted) return; + if (!isDepositsConfirmed() || getMaker().getDepositTx() == null) return; + if (walletHeight.get() - getMaker().getDepositTx().getHeight() < NUM_CONFIRMATIONS_FOR_SCHEDULED_IMPORT) return; + ThreadUtils.execute(() -> { + if (!isInitialized || isShutDownStarted) return; + synchronized (getLock()) { + if (processModel.isImportMultisigHexScheduled()) { + processModel.setImportMultisigHexScheduled(false); + ThreadUtils.submitToPool(() -> importMultisigHex()); + } + } + }, getId()); + } + public void importMultisigHex() { synchronized (walletLock) { synchronized (HavenoUtils.getDaemonLock()) { // lock on daemon because import calls full refresh @@ -1141,6 +1167,9 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { if (removed) wallet.importMultisigHex(multisigHexes.toArray(new String[0])); if (wallet.isMultisigImportNeeded()) throw new IllegalStateException(errorMessage); } + + // remove scheduled import + processModel.setImportMultisigHexScheduled(false); } catch (MoneroError e) { // import multisig hex individually if one is invalid @@ -2350,7 +2379,12 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { return tradeAmountTransferred(); } - public boolean tradeAmountTransferred() { + + /////////////////////////////////////////////////////////////////////////////////////////// + // Private + /////////////////////////////////////////////////////////////////////////////////////////// + + private boolean tradeAmountTransferred() { return isPaymentReceived() || (getDisputeResult() != null && getDisputeResult().getWinner() == DisputeResult.Winner.SELLER); } @@ -2366,11 +2400,6 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { } } - - /////////////////////////////////////////////////////////////////////////////////////////// - // Private - /////////////////////////////////////////////////////////////////////////////////////////// - // lazy initialization private ObjectProperty<BigInteger> getAmountProperty() { if (tradeAmountProperty == null) diff --git a/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java b/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java index d81c4f476a..8521174ca8 100644 --- a/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java +++ b/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java @@ -158,6 +158,9 @@ public class ProcessModel implements Model, PersistablePayload { @Getter @Setter private long tradeProtocolErrorHeight; + @Getter + @Setter + private boolean importMultisigHexScheduled; // We want to indicate the user the state of the message delivery of the // PaymentSentMessage. As well we do an automatic re-send in case it was not ACKed yet. @@ -207,7 +210,8 @@ public class ProcessModel implements Model, PersistablePayload { .setPaymentSentMessageStateArbitrator(paymentSentMessageStatePropertyArbitrator.get().name()) .setBuyerPayoutAmountFromMediation(buyerPayoutAmountFromMediation) .setSellerPayoutAmountFromMediation(sellerPayoutAmountFromMediation) - .setTradeProtocolErrorHeight(tradeProtocolErrorHeight); + .setTradeProtocolErrorHeight(tradeProtocolErrorHeight) + .setImportMultisigHexScheduled(importMultisigHexScheduled); Optional.ofNullable(maker).ifPresent(e -> builder.setMaker((protobuf.TradePeer) maker.toProtoMessage())); Optional.ofNullable(taker).ifPresent(e -> builder.setTaker((protobuf.TradePeer) taker.toProtoMessage())); Optional.ofNullable(arbitrator).ifPresent(e -> builder.setArbitrator((protobuf.TradePeer) arbitrator.toProtoMessage())); @@ -231,6 +235,7 @@ public class ProcessModel implements Model, PersistablePayload { processModel.setBuyerPayoutAmountFromMediation(proto.getBuyerPayoutAmountFromMediation()); processModel.setSellerPayoutAmountFromMediation(proto.getSellerPayoutAmountFromMediation()); processModel.setTradeProtocolErrorHeight(proto.getTradeProtocolErrorHeight()); + processModel.setImportMultisigHexScheduled(proto.getImportMultisigHexScheduled()); // nullable processModel.setPayoutTxSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getPayoutTxSignature())); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositsConfirmedMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositsConfirmedMessage.java index c11df74fae..7e0c85af2d 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositsConfirmedMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositsConfirmedMessage.java @@ -18,7 +18,6 @@ package haveno.core.trade.protocol.tasks; -import haveno.common.ThreadUtils; import haveno.common.taskrunner.TaskRunner; import haveno.core.trade.Trade; import haveno.core.trade.messages.DepositsConfirmedMessage; @@ -63,17 +62,7 @@ public class ProcessDepositsConfirmedMessage extends TradeTask { // update multisig hex if (sender.getUpdatedMultisigHex() == null) { sender.setUpdatedMultisigHex(request.getUpdatedMultisigHex()); - - // try to import multisig hex (retry later) - if (!trade.isPayoutPublished()) { - ThreadUtils.submitToPool(() -> { - try { - trade.importMultisigHex(); - } catch (Exception e) { - log.warn("Error importing multisig hex on deposits confirmed for trade " + trade.getId() + ": " + e.getMessage() + "\n", e); - } - }); - } + trade.scheduleImportMultisigHex(); } // persist diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index 6436052333..9bca09b668 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -1581,6 +1581,7 @@ message ProcessModel { int64 seller_payout_amount_from_mediation = 17; int64 trade_protocol_error_height = 18; string trade_fee_address = 19; + bool import_multisig_hex_scheduled = 20; } message TradePeer { From 63917fe8ccd8a40e75d921960c01da9e1b44c00c Mon Sep 17 00:00:00 2001 From: woodser <woodser@protonmail.com> Date: Tue, 11 Mar 2025 13:42:10 -0400 Subject: [PATCH 21/21] replace sys.outs with log.info in buyer/seller protocols --- .../java/haveno/core/trade/protocol/BuyerAsMakerProtocol.java | 4 ++-- .../java/haveno/core/trade/protocol/BuyerAsTakerProtocol.java | 4 ++-- .../haveno/core/trade/protocol/SellerAsMakerProtocol.java | 2 +- .../haveno/core/trade/protocol/SellerAsTakerProtocol.java | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/protocol/BuyerAsMakerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/BuyerAsMakerProtocol.java index 160e1bee6c..9dc1b64405 100644 --- a/core/src/main/java/haveno/core/trade/protocol/BuyerAsMakerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/BuyerAsMakerProtocol.java @@ -60,8 +60,8 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol public void handleInitTradeRequest(InitTradeRequest message, NodeAddress peer, ErrorMessageHandler errorMessageHandler) { - System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); - ThreadUtils.execute(() -> { + log.info(TradeProtocol.LOG_HIGHLIGHT + "handleInitTradeRequest() for {} {} from {}", trade.getClass().getSimpleName(), trade.getShortId(), peer); + ThreadUtils.execute(() -> { synchronized (trade.getLock()) { latchTrade(); this.errorMessageHandler = errorMessageHandler; diff --git a/core/src/main/java/haveno/core/trade/protocol/BuyerAsTakerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/BuyerAsTakerProtocol.java index 7a5a899e87..927997e611 100644 --- a/core/src/main/java/haveno/core/trade/protocol/BuyerAsTakerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/BuyerAsTakerProtocol.java @@ -68,7 +68,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol @Override public void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) { - System.out.println(getClass().getSimpleName() + ".onTakeOffer()"); + log.info(TradeProtocol.LOG_HIGHLIGHT + "onTakerOffer for {} {}", getClass().getSimpleName(), trade.getShortId()); ThreadUtils.execute(() -> { synchronized (trade.getLock()) { latchTrade(); @@ -99,7 +99,7 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol @Override public void handleInitTradeRequest(InitTradeRequest message, NodeAddress peer) { - System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); + log.info(TradeProtocol.LOG_HIGHLIGHT + "handleInitTradeRequest() for {} {} from {}", trade.getClass().getSimpleName(), trade.getShortId(), peer); ThreadUtils.execute(() -> { synchronized (trade.getLock()) { latchTrade(); diff --git a/core/src/main/java/haveno/core/trade/protocol/SellerAsMakerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/SellerAsMakerProtocol.java index 15d92ff785..9219d0ad7d 100644 --- a/core/src/main/java/haveno/core/trade/protocol/SellerAsMakerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/SellerAsMakerProtocol.java @@ -65,7 +65,7 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc public void handleInitTradeRequest(InitTradeRequest message, NodeAddress peer, ErrorMessageHandler errorMessageHandler) { - System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); + log.info(TradeProtocol.LOG_HIGHLIGHT + "handleInitTradeRequest() for {} {} from {}", trade.getClass().getSimpleName(), trade.getShortId(), peer); ThreadUtils.execute(() -> { synchronized (trade.getLock()) { latchTrade(); diff --git a/core/src/main/java/haveno/core/trade/protocol/SellerAsTakerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/SellerAsTakerProtocol.java index 2332ca2003..f4914efe60 100644 --- a/core/src/main/java/haveno/core/trade/protocol/SellerAsTakerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/SellerAsTakerProtocol.java @@ -68,7 +68,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc @Override public void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) { - System.out.println(getClass().getSimpleName() + ".onTakeOffer()"); + log.info(TradeProtocol.LOG_HIGHLIGHT + "onTakerOffer for {} {}", getClass().getSimpleName(), trade.getShortId()); ThreadUtils.execute(() -> { synchronized (trade.getLock()) { latchTrade(); @@ -99,7 +99,7 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc @Override public void handleInitTradeRequest(InitTradeRequest message, NodeAddress peer) { - System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); + log.info(TradeProtocol.LOG_HIGHLIGHT + "handleInitTradeRequest() for {} {} from {}", trade.getClass().getSimpleName(), trade.getShortId(), peer); ThreadUtils.execute(() -> { synchronized (trade.getLock()) { latchTrade();