From 7a392f3c1ee39fbe1da6114841bc31710fcf191c Mon Sep 17 00:00:00 2001
From: woodser <woodser@protonmail.com>
Date: Mon, 11 Nov 2024 11:13:22 -0500
Subject: [PATCH] defer payout publish if published, skip warning log if
 published

---
 .../main/java/haveno/core/trade/Trade.java    | 19 ++++++++++++-------
 .../tasks/ProcessPaymentReceivedMessage.java  | 11 +++++------
 .../SellerSendPaymentReceivedMessage.java     |  3 ++-
 3 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java
index e7b7584ec9..b540351179 100644
--- a/core/src/main/java/haveno/core/trade/Trade.java
+++ b/core/src/main/java/haveno/core/trade/Trade.java
@@ -1085,11 +1085,12 @@ public void importMultisigHex() {
                         } 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
-                            doPollWallet();
                         }
                     }
                 }
@@ -1205,8 +1206,10 @@ public MoneroTxWallet createPayoutTx() {
                     } catch (IllegalArgumentException | IllegalStateException e) {
                         throw e;
                     } catch (Exception e) {
-                        log.warn("Failed to create payout tx, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage());
                         handleWalletError(e, sourceConnection);
+                        doPollWallet();
+                        if (isPayoutPublished()) break;
+                        log.warn("Failed to create payout tx, 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
                     }
@@ -1265,11 +1268,12 @@ public MoneroTxWallet createDisputePayoutTx(MoneroTxConfig txConfig) {
                         throw e;
                     } catch (Exception e) {
                         if (e.getMessage().contains("not possible")) throw new IllegalArgumentException("Loser payout is too small to cover the mining fee");
-                        log.warn("Failed to create dispute payout tx, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage());
                         handleWalletError(e, sourceConnection);
+                        doPollWallet();
+                        if (isPayoutPublished()) break;
+                        log.warn("Failed to create dispute payout tx, 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
-                        doPollWallet();
                     }
                 }
                 throw new RuntimeException("Failed to create payout tx for " + getClass().getSimpleName() + " " + getId());
@@ -1295,11 +1299,12 @@ public void processPayoutTx(String payoutTxHex, boolean sign, boolean publish) {
                     } catch (IllegalArgumentException | IllegalStateException e) {
                         throw e;
                     } catch (Exception e) {
-                        log.warn("Failed to process payout tx, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage(), e);
                         handleWalletError(e, sourceConnection);
+                        doPollWallet();
+                        if (isPayoutPublished()) break;
+                        log.warn("Failed to process payout tx, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage(), e);
                         if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e;
                         HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying
-                        doPollWallet();
                     } finally {
                         requestSaveWallet();
                         requestPersistence();
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 121d87d85a..2ce29828a4 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
@@ -143,12 +143,10 @@ private void processPayoutTx(PaymentReceivedMessage message) {
         // handle if payout tx not published
         if (!trade.isPayoutPublished()) {
 
-            // wait to sign and publish payout tx if defer flag set (seller recently saw payout tx arrive at buyer)
-            boolean isSigned = message.getSignedPayoutTxHex() != null;
-            boolean deferSignAndPublish = trade instanceof ArbitratorTrade && !isSigned && message.isDeferPublishPayout();
-            if (deferSignAndPublish) {
-                log.info("Deferring signing and publishing payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId());
-                trade.pollWalletNormallyForMs(60000);
+            // wait to publish payout tx if defer flag set from seller (payout is expected)
+            if (message.isDeferPublishPayout()) {
+                log.info("Deferring publishing payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId());
+                if (trade instanceof ArbitratorTrade) trade.pollWalletNormallyForMs(60000); // stop idling arbitrator
                 for (int i = 0; i < 5; i++) {
                     if (trade.isPayoutPublished()) break;
                     HavenoUtils.waitFor(Trade.DEFER_PUBLISH_MS / 5);
@@ -159,6 +157,7 @@ private void processPayoutTx(PaymentReceivedMessage message) {
             // verify and publish payout tx
             if (!trade.isPayoutPublished()) {
                 try {
+                    boolean isSigned = message.getSignedPayoutTxHex() != null;
                     if (isSigned) {
                         log.info("{} {} publishing signed payout tx from seller", trade.getClass().getSimpleName(), trade.getId());
                         trade.processPayoutTx(message.getSignedPayoutTxHex(), false, true);
diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java
index cbfa0e3281..f08fe87946 100644
--- a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java
+++ b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java
@@ -103,6 +103,7 @@ protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) {
             // messages where only the one which gets processed by the peer would be removed we use the same uid. All
             // other data stays the same when we re-send the message at any time later.
             String deterministicId = HavenoUtils.getDeterministicId(trade, PaymentReceivedMessage.class, getReceiverNodeAddress());
+            boolean deferPublishPayout = trade.isPayoutPublished() || trade.getState().ordinal() >= Trade.State.SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG.ordinal(); // informs receiver to expect payout so delay processing
             PaymentReceivedMessage message = new PaymentReceivedMessage(
                     tradeId,
                     processModel.getMyNodeAddress(),
@@ -110,7 +111,7 @@ protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) {
                     trade.getPayoutTxHex() == null ? trade.getSelf().getUnsignedPayoutTxHex() : null, // unsigned // TODO: phase in after next update to clear old style trades
                     trade.getPayoutTxHex() == null ? null : trade.getPayoutTxHex(), // signed
                     trade.getSelf().getUpdatedMultisigHex(),
-                    trade.getState().ordinal() >= Trade.State.SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG.ordinal(), // informs to expect payout
+                    deferPublishPayout,
                     trade.getTradePeer().getAccountAgeWitness(),
                     signedWitness,
                     getReceiver() == trade.getArbitrator() ? trade.getBuyer().getPaymentSentMessage() : null // buyer already has payment sent message