fix payment sent message state property after improper shut down

This commit is contained in:
woodser 2024-01-11 10:22:38 -05:00
parent db155283be
commit 2b9d0ef5a6
4 changed files with 34 additions and 11 deletions

View File

@ -32,6 +32,7 @@ import haveno.common.util.Utilities;
import haveno.core.api.XmrConnectionService; import haveno.core.api.XmrConnectionService;
import haveno.core.monetary.Price; import haveno.core.monetary.Price;
import haveno.core.monetary.Volume; import haveno.core.monetary.Volume;
import haveno.core.network.MessageState;
import haveno.core.offer.Offer; import haveno.core.offer.Offer;
import haveno.core.offer.OfferDirection; import haveno.core.offer.OfferDirection;
import haveno.core.payment.payload.PaymentAccountPayload; import haveno.core.payment.payload.PaymentAccountPayload;
@ -693,6 +694,13 @@ public abstract class Trade implements Tradable, Model {
xmrWalletService.addWalletListener(idlePayoutSyncer); xmrWalletService.addWalletListener(idlePayoutSyncer);
} }
// TODO: trader's payment sent message state property can become unsynced (after improper shut down?)
MessageState expectedState = getPaymentSentMessageState();
if (!isArbitrator() && 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);
}
// trade is initialized // trade is initialized
isInitialized = true; isInitialized = true;
@ -1569,6 +1577,24 @@ public abstract class Trade implements Tradable, Model {
throw new IllegalArgumentException("Trade is not buyer, seller, or arbitrator"); throw new IllegalArgumentException("Trade is not buyer, seller, or arbitrator");
} }
public MessageState getPaymentSentMessageState() {
if (isPaymentReceived()) return MessageState.ACKNOWLEDGED;
if (processModel.getPaymentSentMessageStateProperty().get() == MessageState.ACKNOWLEDGED) return MessageState.ACKNOWLEDGED;
switch (state) {
case BUYER_SENT_PAYMENT_SENT_MSG:
case BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG:
return MessageState.SENT;
case BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG:
return MessageState.STORED_IN_MAILBOX;
case SELLER_RECEIVED_PAYMENT_SENT_MSG:
return MessageState.ARRIVED;
case BUYER_SEND_FAILED_PAYMENT_SENT_MSG:
return MessageState.FAILED;
default:
return null;
}
}
public String getPeerRole(TradePeer peer) { public String getPeerRole(TradePeer peer) {
if (peer == getBuyer()) return "Buyer"; if (peer == getBuyer()) return "Buyer";
if (peer == getSeller()) return "Seller"; if (peer == getSeller()) return "Seller";

View File

@ -770,7 +770,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
trade.setMyNodeAddress(); // TODO: this is a hack to update my node address before verifying the message trade.setMyNodeAddress(); // TODO: this is a hack to update my node address before verifying the message
TradePeer peer = trade.getTradePeer(address); TradePeer peer = trade.getTradePeer(address);
if (peer == null) { if (peer == null) {
log.warn("Cannot get peer's pub key ring because peer is not maker, taker, or arbitrator. Their address might have changed: " + peer); log.warn("Cannot get peer's pub key ring because peer is not maker, taker, or arbitrator. Their address might have changed: " + address);
return null; return null;
} }
return peer.getPubKeyRing(); return peer.getPubKeyRing();

View File

@ -191,14 +191,12 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
}); });
messageStateSubscription = EasyBind.subscribe(trade.getProcessModel().getPaymentSentMessageStateProperty(), this::onMessageStateChanged); messageStateSubscription = EasyBind.subscribe(trade.getProcessModel().getPaymentSentMessageStateProperty(), this::onMessageStateChanged);
} }
} }
} }
public void setMessageStateProperty(MessageState messageState) { public void setMessageStateProperty(MessageState messageState) {
// ARRIVED is set internally after ACKNOWLEDGED, otherwise warn if subsequent states received if (messageStateProperty.get() == MessageState.ACKNOWLEDGED) {
if ((messageStateProperty.get() == MessageState.ACKNOWLEDGED && messageState != MessageState.ARRIVED) || messageStateProperty.get() == MessageState.ARRIVED) { log.warn("We have already an ACKNOWLEDGED message received. " +
log.warn("We have already an ACKNOWLEDGED/ARRIVED message received. " +
"We would not expect any other message after that. Received messageState={}", messageState); "We would not expect any other message after that. Received messageState={}", messageState);
return; return;
} }

View File

@ -22,7 +22,6 @@ import haveno.common.UserThread;
import haveno.common.app.DevEnv; import haveno.common.app.DevEnv;
import haveno.common.util.Tuple4; import haveno.common.util.Tuple4;
import haveno.core.locale.Res; import haveno.core.locale.Res;
import haveno.core.network.MessageState;
import haveno.core.offer.Offer; import haveno.core.offer.Offer;
import haveno.core.payment.PaymentAccount; import haveno.core.payment.PaymentAccount;
import haveno.core.payment.PaymentAccountUtil; import haveno.core.payment.PaymentAccountUtil;
@ -158,7 +157,7 @@ public class BuyerStep2View extends TradeStepView {
case BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG: case BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG:
busyAnimation.play(); busyAnimation.play();
statusLabel.setText(Res.get("shared.sendingConfirmation")); statusLabel.setText(Res.get("shared.sendingConfirmation"));
model.setMessageStateProperty(MessageState.SENT); model.setMessageStateProperty(trade.getPaymentSentMessageState());
timeoutTimer = UserThread.runAfter(() -> { timeoutTimer = UserThread.runAfter(() -> {
busyAnimation.stop(); busyAnimation.stop();
statusLabel.setText(Res.get("shared.sendingConfirmationAgain")); statusLabel.setText(Res.get("shared.sendingConfirmationAgain"));
@ -167,18 +166,18 @@ public class BuyerStep2View extends TradeStepView {
case BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG: case BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG:
busyAnimation.stop(); busyAnimation.stop();
statusLabel.setText(Res.get("shared.messageStoredInMailbox")); statusLabel.setText(Res.get("shared.messageStoredInMailbox"));
model.setMessageStateProperty(MessageState.STORED_IN_MAILBOX); model.setMessageStateProperty(trade.getPaymentSentMessageState());
break; break;
case SELLER_RECEIVED_PAYMENT_SENT_MSG: case SELLER_RECEIVED_PAYMENT_SENT_MSG:
busyAnimation.stop(); busyAnimation.stop();
statusLabel.setText(Res.get("shared.messageArrived")); statusLabel.setText(Res.get("shared.messageArrived"));
model.setMessageStateProperty(MessageState.ARRIVED); model.setMessageStateProperty(trade.getPaymentSentMessageState());
break; break;
case BUYER_SEND_FAILED_PAYMENT_SENT_MSG: case BUYER_SEND_FAILED_PAYMENT_SENT_MSG:
// We get a popup and the trade closed, so we dont need to show anything here // We get a popup and the trade closed, so we dont need to show anything here
busyAnimation.stop(); busyAnimation.stop();
statusLabel.setText(""); statusLabel.setText("");
model.setMessageStateProperty(MessageState.FAILED); model.setMessageStateProperty(trade.getPaymentSentMessageState());
break; break;
default: default:
log.warn("Unexpected case: State={}, tradeId={} ", state.name(), trade.getId()); log.warn("Unexpected case: State={}, tradeId={} ", state.name(), trade.getId());