mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-07-26 16:35:18 -04:00
process mailbox messages in sequential order per trade
This commit is contained in:
parent
da8474a0f4
commit
846a8634e5
7 changed files with 135 additions and 73 deletions
|
@ -29,8 +29,6 @@ import haveno.core.support.messages.ChatMessage;
|
|||
import haveno.core.support.messages.SupportMessage;
|
||||
import haveno.core.trade.Trade;
|
||||
import haveno.core.trade.TradeManager;
|
||||
import haveno.core.trade.protocol.TradeProtocol;
|
||||
import haveno.core.trade.protocol.TradeProtocol.MailboxMessageComparator;
|
||||
import haveno.core.xmr.wallet.XmrWalletService;
|
||||
import haveno.network.p2p.AckMessage;
|
||||
import haveno.network.p2p.AckMessageSourceType;
|
||||
|
@ -40,10 +38,10 @@ import haveno.network.p2p.P2PService;
|
|||
import haveno.network.p2p.SendMailboxMessageListener;
|
||||
import haveno.network.p2p.mailbox.MailboxMessage;
|
||||
import haveno.network.p2p.mailbox.MailboxMessageService;
|
||||
import haveno.network.p2p.mailbox.MailboxMessageService.DecryptedMessageWithPubKeyComparator;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -82,9 +80,9 @@ public abstract class SupportManager {
|
|||
|
||||
// We get first the message handler called then the onBootstrapped
|
||||
p2PService.addDecryptedDirectMessageListener((decryptedMessageWithPubKey, senderAddress) -> {
|
||||
if (isReady()) applyDirectMessage(decryptedMessageWithPubKey);
|
||||
else {
|
||||
synchronized (lock) {
|
||||
synchronized (lock) {
|
||||
if (isReady()) applyDirectMessage(decryptedMessageWithPubKey);
|
||||
else {
|
||||
// As decryptedDirectMessageWithPubKeys is a CopyOnWriteArraySet we do not need to check if it was already stored
|
||||
decryptedDirectMessageWithPubKeys.add(decryptedMessageWithPubKey);
|
||||
tryApplyMessages();
|
||||
|
@ -92,9 +90,9 @@ public abstract class SupportManager {
|
|||
}
|
||||
});
|
||||
mailboxMessageService.addDecryptedMailboxListener((decryptedMessageWithPubKey, senderAddress) -> {
|
||||
if (isReady()) applyMailboxMessage(decryptedMessageWithPubKey);
|
||||
else {
|
||||
synchronized (lock) {
|
||||
synchronized (lock) {
|
||||
if (isReady()) applyMailboxMessage(decryptedMessageWithPubKey);
|
||||
else {
|
||||
// As decryptedMailboxMessageWithPubKeys is a CopyOnWriteArraySet we do not need to check if it was already stored
|
||||
decryptedDirectMessageWithPubKeys.add(decryptedMessageWithPubKey);
|
||||
tryApplyMessages();
|
||||
|
@ -395,22 +393,4 @@ public abstract class SupportManager {
|
|||
mailboxMessageService.removeMailboxMsg(ackMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DecryptedMessageWithPubKeyComparator implements Comparator<DecryptedMessageWithPubKey> {
|
||||
|
||||
MailboxMessageComparator mailboxMessageComparator;
|
||||
public DecryptedMessageWithPubKeyComparator() {
|
||||
mailboxMessageComparator = new TradeProtocol.MailboxMessageComparator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(DecryptedMessageWithPubKey m1, DecryptedMessageWithPubKey m2) {
|
||||
if (m1.getNetworkEnvelope() instanceof MailboxMessage) {
|
||||
if (m2.getNetworkEnvelope() instanceof MailboxMessage) return mailboxMessageComparator.compare((MailboxMessage) m1.getNetworkEnvelope(), (MailboxMessage) m2.getNetworkEnvelope());
|
||||
else return 1;
|
||||
} else {
|
||||
return m2.getNetworkEnvelope() instanceof MailboxMessage ? -1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -354,6 +354,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
disputeList.add(dispute);
|
||||
}
|
||||
|
||||
// create dispute opened message
|
||||
NodeAddress agentNodeAddress = getAgentNodeAddress(dispute);
|
||||
DisputeOpenedMessage disputeOpenedMessage = new DisputeOpenedMessage(dispute,
|
||||
p2PService.getAddress(),
|
||||
|
@ -367,6 +368,8 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(),
|
||||
chatMessage.getUid());
|
||||
recordPendingMessage(disputeOpenedMessage.getClass().getSimpleName());
|
||||
|
||||
// send dispute opened message
|
||||
mailboxMessageService.sendEncryptedMailboxMessage(agentNodeAddress,
|
||||
dispute.getAgentPubKeyRing(),
|
||||
disputeOpenedMessage,
|
||||
|
@ -436,7 +439,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
// arbitrator receives dispute opened message from opener, opener's peer receives from arbitrator
|
||||
protected void handleDisputeOpenedMessage(DisputeOpenedMessage message) {
|
||||
Dispute dispute = message.getDispute();
|
||||
log.info("{}.onDisputeOpenedMessage() with trade {}, dispute {}", getClass().getSimpleName(), dispute.getTradeId(), dispute.getId());
|
||||
log.info("Processing {} with trade {}, dispute {}", message.getClass().getSimpleName(), dispute.getTradeId(), dispute.getId());
|
||||
|
||||
// get trade
|
||||
Trade trade = tradeManager.getTrade(dispute.getTradeId());
|
||||
|
@ -467,6 +470,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
DisputeValidation.validateSenderNodeAddress(dispute, message.getSenderNodeAddress());
|
||||
//DisputeValidation.testIfDisputeTriesReplay(dispute, disputeList.getList());
|
||||
} catch (DisputeValidation.ValidationException e) {
|
||||
e.printStackTrace();
|
||||
validationExceptions.add(e);
|
||||
throw e;
|
||||
}
|
||||
|
@ -476,6 +480,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
try {
|
||||
DisputeValidation.validatePaymentAccountPayload(dispute);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.warn(e.getMessage());
|
||||
trade.prependErrorMessage(e.getMessage());
|
||||
}
|
||||
|
@ -499,7 +504,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
|
||||
// update multisig hex
|
||||
if (message.getUpdatedMultisigHex() != null) sender.setUpdatedMultisigHex(message.getUpdatedMultisigHex());
|
||||
trade.importMultisigHex();
|
||||
if (trade.walletExists()) trade.importMultisigHex();
|
||||
|
||||
// add chat message with price info
|
||||
if (trade instanceof ArbitratorTrade) addPriceInfoMessage(dispute, 0);
|
||||
|
@ -518,8 +523,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
errorMessage = null;
|
||||
} else {
|
||||
// valid case if both have opened a dispute and agent was not online
|
||||
log.debug("We got a dispute already open for that trade and trading peer. TradeId = {}",
|
||||
dispute.getTradeId());
|
||||
log.debug("We got a dispute already open for that trade and trading peer. TradeId = {}", dispute.getTradeId());
|
||||
}
|
||||
|
||||
// add chat message with mediation info if applicable
|
||||
|
@ -529,6 +533,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorMessage = e.getMessage();
|
||||
log.warn(errorMessage);
|
||||
if (trade != null) trade.setErrorMessage(errorMessage);
|
||||
|
|
|
@ -116,7 +116,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
log.info("Received {} from {} with tradeId {} and uid {}",
|
||||
message.getClass().getSimpleName(), message.getSenderNodeAddress(), message.getTradeId(), message.getUid());
|
||||
|
||||
new Thread(() -> {
|
||||
HavenoUtils.runTask(message.getTradeId(), () -> {
|
||||
if (message instanceof DisputeOpenedMessage) {
|
||||
handleDisputeOpenedMessage((DisputeOpenedMessage) message);
|
||||
} else if (message instanceof ChatMessage) {
|
||||
|
@ -126,7 +126,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
} else {
|
||||
log.warn("Unsupported message at dispatchMessage. message={}", message);
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
String summaryText = chatMessage.getMessage();
|
||||
if (summaryText == null || summaryText.isEmpty()) throw new IllegalArgumentException("Summary text for dispute is missing, tradeId=" + tradeId + (dispute == null ? "" : ", disputeId=" + dispute.getId()));
|
||||
if (dispute != null) DisputeSummaryVerification.verifySignature(summaryText, dispute.getAgentPubKeyRing()); // use dispute's arbitrator pub key ring
|
||||
else DisputeSummaryVerification.verifySignature(summaryText, arbitratorManager); // verify using registered arbitrator (will fail is arbitrator is unregistered)
|
||||
else DisputeSummaryVerification.verifySignature(summaryText, arbitratorManager); // verify using registered arbitrator (will fail if arbitrator is unregistered)
|
||||
|
||||
// save dispute closed message for reprocessing
|
||||
trade.getArbitrator().setDisputeClosedMessage(disputeClosedMessage);
|
||||
|
@ -253,11 +253,9 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
trade.saveWallet();
|
||||
}
|
||||
|
||||
// import multisig hex
|
||||
if (trade.walletExists()) {
|
||||
if (disputeClosedMessage.getUpdatedMultisigHex() != null) trade.getArbitrator().setUpdatedMultisigHex(disputeClosedMessage.getUpdatedMultisigHex());
|
||||
trade.importMultisigHex();
|
||||
}
|
||||
// update multisig hex
|
||||
if (disputeClosedMessage.getUpdatedMultisigHex() != null) trade.getArbitrator().setUpdatedMultisigHex(disputeClosedMessage.getUpdatedMultisigHex());
|
||||
if (trade.walletExists()) trade.importMultisigHex();
|
||||
|
||||
// attempt to sign and publish dispute payout tx if given and not already published
|
||||
if (disputeClosedMessage.getUnsignedPayoutTxHex() != null && !trade.isPayoutPublished()) {
|
||||
|
@ -270,7 +268,9 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
}
|
||||
|
||||
// sign and publish dispute payout tx if peer still has not published
|
||||
if (!trade.isPayoutPublished()) {
|
||||
if (trade.isPayoutPublished()) {
|
||||
log.info("Dispute payout tx already published for {} {}", trade.getClass().getSimpleName(), trade.getId());
|
||||
} else {
|
||||
try {
|
||||
log.info("Signing and publishing dispute payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId());
|
||||
signAndPublishDisputePayoutTx(trade);
|
||||
|
@ -284,14 +284,17 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
throw new RuntimeException("Failed to sign and publish dispute payout tx from arbitrator: " + e.getMessage() + ". TradeId = " + tradeId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.info("Dispute payout tx already published for {} {}", trade.getClass().getSimpleName(), trade.getId());
|
||||
}
|
||||
} else {
|
||||
if (trade.isPayoutPublished()) log.info("Dispute payout tx already published for {} {}", trade.getClass().getSimpleName(), trade.getId());
|
||||
else if (disputeClosedMessage.getUnsignedPayoutTxHex() == null) log.info("{} did not receive unsigned dispute payout tx for trade {} because the arbitrator did not have their updated multisig info (can happen if trader went offline after trade started)", trade.getClass().getSimpleName(), trade.getId());
|
||||
}
|
||||
|
||||
// complete disputed trade
|
||||
if (trade.isPayoutPublished()) {
|
||||
tradeManager.closeDisputedTrade(trade.getId(), Trade.DisputeState.DISPUTE_CLOSED);
|
||||
}
|
||||
|
||||
// We use the chatMessage as we only persist those not the DisputeClosedMessage.
|
||||
// If we would use the DisputeClosedMessage we could not lookup for the msg when we receive the AckMessage.
|
||||
sendAckMessage(chatMessage, dispute.getAgentPubKeyRing(), true, null);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue