diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index e7b7584e..b5403511 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 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 - doPollWallet(); } } } @@ -1205,8 +1206,10 @@ public abstract class Trade extends XmrWalletBase implements Tradable, Model { } 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 abstract class Trade extends XmrWalletBase implements Tradable, Model { 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 abstract class Trade extends XmrWalletBase implements Tradable, Model { } 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 121d87d8..2ce29828 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 @@ public class ProcessPaymentReceivedMessage extends TradeTask { // 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 @@ public class ProcessPaymentReceivedMessage extends TradeTask { // 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 cbfa0e32..f08fe879 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 @@ public abstract class SellerSendPaymentReceivedMessage extends SendMailboxMessag // 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 @@ public abstract class SellerSendPaymentReceivedMessage extends SendMailboxMessag 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