Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix payment sent message state property after improper shut down #748

Merged
merged 2 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions core/src/main/java/haveno/core/trade/Trade.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import haveno.core.api.XmrConnectionService;
import haveno.core.monetary.Price;
import haveno.core.monetary.Volume;
import haveno.core.network.MessageState;
import haveno.core.offer.Offer;
import haveno.core.offer.OfferDirection;
import haveno.core.payment.payload.PaymentAccountPayload;
Expand Down Expand Up @@ -693,6 +694,13 @@ public void initialize(ProcessModelServiceProvider serviceProvider) {
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
isInitialized = true;

Expand Down Expand Up @@ -1569,6 +1577,24 @@ public String getRole() {
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) {
if (peer == getBuyer()) return "Buyer";
if (peer == getSeller()) return "Seller";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ private PubKeyRing getPeersPubKeyRing(NodeAddress address) {
trade.setMyNodeAddress(); // TODO: this is a hack to update my node address before verifying the message
TradePeer peer = trade.getTradePeer(address);
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 peer.getPubKeyRing();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ protected void run() {

// skip if already acked by receiver
if (ackedByReceiver()) {
complete();
if (!isCompleted()) complete();
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,12 @@ public void onSelectedItemChanged(PendingTradesListItem selectedItem) {
});
messageStateSubscription = EasyBind.subscribe(trade.getProcessModel().getPaymentSentMessageStateProperty(), this::onMessageStateChanged);
}

}
}

public void setMessageStateProperty(MessageState messageState) {
// ARRIVED is set internally after ACKNOWLEDGED, otherwise warn if subsequent states received
if ((messageStateProperty.get() == MessageState.ACKNOWLEDGED && messageState != MessageState.ARRIVED) || messageStateProperty.get() == MessageState.ARRIVED) {
log.warn("We have already an ACKNOWLEDGED/ARRIVED message received. " +
if (messageStateProperty.get() == MessageState.ACKNOWLEDGED) {
log.warn("We have already an ACKNOWLEDGED message received. " +
"We would not expect any other message after that. Received messageState={}", messageState);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import haveno.common.app.DevEnv;
import haveno.common.util.Tuple4;
import haveno.core.locale.Res;
import haveno.core.network.MessageState;
import haveno.core.offer.Offer;
import haveno.core.payment.PaymentAccount;
import haveno.core.payment.PaymentAccountUtil;
Expand Down Expand Up @@ -158,7 +157,7 @@ public void activate() {
case BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG:
busyAnimation.play();
statusLabel.setText(Res.get("shared.sendingConfirmation"));
model.setMessageStateProperty(MessageState.SENT);
model.setMessageStateProperty(trade.getPaymentSentMessageState());
timeoutTimer = UserThread.runAfter(() -> {
busyAnimation.stop();
statusLabel.setText(Res.get("shared.sendingConfirmationAgain"));
Expand All @@ -167,25 +166,25 @@ public void activate() {
case BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG:
busyAnimation.stop();
statusLabel.setText(Res.get("shared.messageStoredInMailbox"));
model.setMessageStateProperty(MessageState.STORED_IN_MAILBOX);
model.setMessageStateProperty(trade.getPaymentSentMessageState());
break;
case SELLER_RECEIVED_PAYMENT_SENT_MSG:
busyAnimation.stop();
statusLabel.setText(Res.get("shared.messageArrived"));
model.setMessageStateProperty(MessageState.ARRIVED);
model.setMessageStateProperty(trade.getPaymentSentMessageState());
break;
case BUYER_SEND_FAILED_PAYMENT_SENT_MSG:
// We get a popup and the trade closed, so we dont need to show anything here
busyAnimation.stop();
statusLabel.setText("");
model.setMessageStateProperty(MessageState.FAILED);
model.setMessageStateProperty(trade.getPaymentSentMessageState());
break;
default:
log.warn("Unexpected case: State={}, tradeId={} ", state.name(), trade.getId());
busyAnimation.stop();
statusLabel.setText(Res.get("shared.sendingConfirmationAgain"));
break;
}
}
}
});
}
Expand Down
Loading