mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-12-23 03:59:36 +00:00
resend dispute closed message with payout tx on updated multisig info
advance dispute state if progress SupportManager processes messages in order re-arrange domain initialization to fix null pub key in DisputeManager
This commit is contained in:
parent
533639bd19
commit
23393bb4b8
7 changed files with 176 additions and 46 deletions
|
@ -176,6 +176,10 @@ public class DomainInitialisation {
|
||||||
|
|
||||||
PersistenceManager.onAllServicesInitialized();
|
PersistenceManager.onAllServicesInitialized();
|
||||||
|
|
||||||
|
arbitratorManager.onAllServicesInitialized();
|
||||||
|
mediatorManager.onAllServicesInitialized();
|
||||||
|
refundAgentManager.onAllServicesInitialized();
|
||||||
|
|
||||||
tradeManager.onAllServicesInitialized();
|
tradeManager.onAllServicesInitialized();
|
||||||
arbitrationManager.onAllServicesInitialized();
|
arbitrationManager.onAllServicesInitialized();
|
||||||
mediationManager.onAllServicesInitialized();
|
mediationManager.onAllServicesInitialized();
|
||||||
|
@ -192,10 +196,6 @@ public class DomainInitialisation {
|
||||||
|
|
||||||
walletAppSetup.setRejectedTxErrorMessageHandler(rejectedTxErrorMessageHandler, openOfferManager, tradeManager);
|
walletAppSetup.setRejectedTxErrorMessageHandler(rejectedTxErrorMessageHandler, openOfferManager, tradeManager);
|
||||||
|
|
||||||
arbitratorManager.onAllServicesInitialized();
|
|
||||||
mediatorManager.onAllServicesInitialized();
|
|
||||||
refundAgentManager.onAllServicesInitialized();
|
|
||||||
|
|
||||||
privateNotificationManager.privateNotificationProperty().addListener((observable, oldValue, newValue) -> {
|
privateNotificationManager.privateNotificationProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
if (displayPrivateNotificationHandler != null)
|
if (displayPrivateNotificationHandler != null)
|
||||||
displayPrivateNotificationHandler.accept(newValue);
|
displayPrivateNotificationHandler.accept(newValue);
|
||||||
|
|
|
@ -22,13 +22,15 @@ import bisq.core.api.CoreNotificationService;
|
||||||
import bisq.core.locale.Res;
|
import bisq.core.locale.Res;
|
||||||
import bisq.core.support.messages.ChatMessage;
|
import bisq.core.support.messages.ChatMessage;
|
||||||
import bisq.core.support.messages.SupportMessage;
|
import bisq.core.support.messages.SupportMessage;
|
||||||
|
import bisq.core.trade.protocol.TradeProtocol;
|
||||||
|
import bisq.core.trade.protocol.TradeProtocol.MailboxMessageComparator;
|
||||||
import bisq.network.p2p.AckMessage;
|
import bisq.network.p2p.AckMessage;
|
||||||
import bisq.network.p2p.AckMessageSourceType;
|
import bisq.network.p2p.AckMessageSourceType;
|
||||||
import bisq.network.p2p.DecryptedMessageWithPubKey;
|
import bisq.network.p2p.DecryptedMessageWithPubKey;
|
||||||
import bisq.network.p2p.NodeAddress;
|
import bisq.network.p2p.NodeAddress;
|
||||||
import bisq.network.p2p.P2PService;
|
import bisq.network.p2p.P2PService;
|
||||||
import bisq.network.p2p.SendMailboxMessageListener;
|
import bisq.network.p2p.SendMailboxMessageListener;
|
||||||
|
import bisq.network.p2p.mailbox.MailboxMessage;
|
||||||
import bisq.network.p2p.mailbox.MailboxMessageService;
|
import bisq.network.p2p.mailbox.MailboxMessageService;
|
||||||
|
|
||||||
import bisq.common.Timer;
|
import bisq.common.Timer;
|
||||||
|
@ -36,6 +38,7 @@ import bisq.common.UserThread;
|
||||||
import bisq.common.crypto.PubKeyRing;
|
import bisq.common.crypto.PubKeyRing;
|
||||||
import bisq.common.proto.network.NetworkEnvelope;
|
import bisq.common.proto.network.NetworkEnvelope;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -322,9 +325,27 @@ public abstract class SupportManager {
|
||||||
|
|
||||||
private void applyMessages() {
|
private void applyMessages() {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
decryptedDirectMessageWithPubKeys.forEach(decryptedMessageWithPubKey -> applyDirectMessage(decryptedMessageWithPubKey));
|
|
||||||
|
// apply non-mailbox messages
|
||||||
|
decryptedDirectMessageWithPubKeys.stream()
|
||||||
|
.filter(e -> !(e.getNetworkEnvelope() instanceof MailboxMessage))
|
||||||
|
.forEach(decryptedMessageWithPubKey -> applyDirectMessage(decryptedMessageWithPubKey));
|
||||||
|
decryptedMailboxMessageWithPubKeys.stream()
|
||||||
|
.filter(e -> !(e.getNetworkEnvelope() instanceof MailboxMessage))
|
||||||
|
.forEach(decryptedMessageWithPubKey -> applyMailboxMessage(decryptedMessageWithPubKey));
|
||||||
|
|
||||||
|
// apply mailbox messages in order
|
||||||
|
decryptedDirectMessageWithPubKeys.stream()
|
||||||
|
.filter(e -> (e.getNetworkEnvelope() instanceof MailboxMessage))
|
||||||
|
.sorted(new DecryptedMessageWithPubKeyComparator())
|
||||||
|
.forEach(decryptedMessageWithPubKey -> applyDirectMessage(decryptedMessageWithPubKey));
|
||||||
|
decryptedMailboxMessageWithPubKeys.stream()
|
||||||
|
.filter(e -> (e.getNetworkEnvelope() instanceof MailboxMessage))
|
||||||
|
.sorted(new DecryptedMessageWithPubKeyComparator())
|
||||||
|
.forEach(decryptedMessageWithPubKey -> applyMailboxMessage(decryptedMessageWithPubKey));
|
||||||
|
|
||||||
|
// clear messages
|
||||||
decryptedDirectMessageWithPubKeys.clear();
|
decryptedDirectMessageWithPubKeys.clear();
|
||||||
decryptedMailboxMessageWithPubKeys.forEach(decryptedMessageWithPubKey -> applyMailboxMessage(decryptedMessageWithPubKey));
|
|
||||||
decryptedMailboxMessageWithPubKeys.clear();
|
decryptedMailboxMessageWithPubKeys.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,4 +372,22 @@ public abstract class SupportManager {
|
||||||
mailboxMessageService.removeMailboxMsg(ackMessage);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
protected final TradeManager tradeManager;
|
protected final TradeManager tradeManager;
|
||||||
protected final ClosedTradableManager closedTradableManager;
|
protected final ClosedTradableManager closedTradableManager;
|
||||||
protected final OpenOfferManager openOfferManager;
|
protected final OpenOfferManager openOfferManager;
|
||||||
protected final PubKeyRing pubKeyRing;
|
protected final KeyRing keyRing;
|
||||||
protected final DisputeListService<T> disputeListService;
|
protected final DisputeListService<T> disputeListService;
|
||||||
private final Config config;
|
private final Config config;
|
||||||
private final PriceFeedService priceFeedService;
|
private final PriceFeedService priceFeedService;
|
||||||
|
@ -105,9 +105,6 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
@Getter
|
@Getter
|
||||||
protected final ObservableList<TradeDataValidation.ValidationException> validationExceptions =
|
protected final ObservableList<TradeDataValidation.ValidationException> validationExceptions =
|
||||||
FXCollections.observableArrayList();
|
FXCollections.observableArrayList();
|
||||||
@Getter
|
|
||||||
private final KeyPair signatureKeyPair;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor
|
// Constructor
|
||||||
|
@ -132,18 +129,20 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
this.tradeManager = tradeManager;
|
this.tradeManager = tradeManager;
|
||||||
this.closedTradableManager = closedTradableManager;
|
this.closedTradableManager = closedTradableManager;
|
||||||
this.openOfferManager = openOfferManager;
|
this.openOfferManager = openOfferManager;
|
||||||
this.pubKeyRing = keyRing.getPubKeyRing();
|
this.keyRing = keyRing;
|
||||||
signatureKeyPair = keyRing.getSignatureKeyPair();
|
|
||||||
this.disputeListService = disputeListService;
|
this.disputeListService = disputeListService;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.priceFeedService = priceFeedService;
|
this.priceFeedService = priceFeedService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Implement template methods
|
// Implement template methods
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public KeyPair getSignatureKeyPair() {
|
||||||
|
return keyRing.getSignatureKeyPair();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void requestPersistence() {
|
public void requestPersistence() {
|
||||||
disputeListService.requestPersistence();
|
disputeListService.requestPersistence();
|
||||||
|
@ -204,7 +203,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
// Abstract methods
|
// Abstract methods
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// We get that message at both peers. The dispute object is in context of the trader
|
// We get this message at both peers. The dispute object is in context of the trader
|
||||||
public abstract void handleDisputeClosedMessage(DisputeClosedMessage disputeClosedMessage);
|
public abstract void handleDisputeClosedMessage(DisputeClosedMessage disputeClosedMessage);
|
||||||
|
|
||||||
public abstract NodeAddress getAgentNodeAddress(Dispute dispute);
|
public abstract NodeAddress getAgentNodeAddress(Dispute dispute);
|
||||||
|
@ -292,7 +291,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTrader(Dispute dispute) {
|
public boolean isTrader(Dispute dispute) {
|
||||||
return pubKeyRing.equals(dispute.getTraderPubKeyRing());
|
return keyRing.getPubKeyRing().equals(dispute.getTraderPubKeyRing());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Dispute> findOwnDispute(String tradeId) {
|
public Optional<Dispute> findOwnDispute(String tradeId) {
|
||||||
|
@ -352,7 +351,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
ChatMessage chatMessage = new ChatMessage(
|
ChatMessage chatMessage = new ChatMessage(
|
||||||
getSupportType(),
|
getSupportType(),
|
||||||
dispute.getTradeId(),
|
dispute.getTradeId(),
|
||||||
pubKeyRing.hashCode(),
|
keyRing.getPubKeyRing().hashCode(),
|
||||||
false,
|
false,
|
||||||
Res.get("support.systemMsg", sysMsg),
|
Res.get("support.systemMsg", sysMsg),
|
||||||
p2PService.getAddress());
|
p2PService.getAddress());
|
||||||
|
@ -389,7 +388,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
// We use the chatMessage wrapped inside the openNewDisputeMessage for
|
// We use the chatMessage wrapped inside the openNewDisputeMessage for
|
||||||
// the state, as that is displayed to the user and we only persist that msg
|
// the state, as that is displayed to the user and we only persist that msg
|
||||||
chatMessage.setArrived(true);
|
chatMessage.setArrived(true);
|
||||||
trade.setDisputeState(Trade.DisputeState.DISPUTE_OPENED);
|
trade.setDisputeStateIfProgress(Trade.DisputeState.DISPUTE_OPENED);
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
resultHandler.handleResult();
|
resultHandler.handleResult();
|
||||||
}
|
}
|
||||||
|
@ -405,7 +404,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
// We use the chatMessage wrapped inside the openNewDisputeMessage for
|
// We use the chatMessage wrapped inside the openNewDisputeMessage for
|
||||||
// the state, as that is displayed to the user and we only persist that msg
|
// the state, as that is displayed to the user and we only persist that msg
|
||||||
chatMessage.setStoredInMailbox(true);
|
chatMessage.setStoredInMailbox(true);
|
||||||
trade.setDisputeState(Trade.DisputeState.DISPUTE_OPENED);
|
trade.setDisputeStateIfProgress(Trade.DisputeState.DISPUTE_OPENED);
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
resultHandler.handleResult();
|
resultHandler.handleResult();
|
||||||
}
|
}
|
||||||
|
@ -507,7 +506,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
Optional<Dispute> storedDisputeOptional = findDispute(dispute);
|
Optional<Dispute> storedDisputeOptional = findDispute(dispute);
|
||||||
if (!storedDisputeOptional.isPresent()) {
|
if (!storedDisputeOptional.isPresent()) {
|
||||||
disputeList.add(dispute);
|
disputeList.add(dispute);
|
||||||
trade.setDisputeState(Trade.DisputeState.DISPUTE_OPENED);
|
trade.setDisputeStateIfProgress(Trade.DisputeState.DISPUTE_OPENED);
|
||||||
|
|
||||||
// send dispute opened message to peer if arbitrator
|
// send dispute opened message to peer if arbitrator
|
||||||
if (trade.isArbitrator()) sendDisputeOpenedMessageToPeer(dispute, contract, dispute.isDisputeOpenerIsBuyer() ? contract.getSellerPubKeyRing() : contract.getBuyerPubKeyRing(), trade.getSelf().getUpdatedMultisigHex());
|
if (trade.isArbitrator()) sendDisputeOpenedMessageToPeer(dispute, contract, dispute.isDisputeOpenerIsBuyer() ? contract.getSellerPubKeyRing() : contract.getBuyerPubKeyRing(), trade.getSelf().getUpdatedMultisigHex());
|
||||||
|
@ -703,7 +702,9 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
// create dispute payout tx if not given
|
// create dispute payout tx if not given
|
||||||
if (payoutTx == null) payoutTx = createDisputePayoutTx(trade, dispute, disputeResult, false); // can be null if already published or we don't have receiver's multisig hex
|
if (payoutTx == null) payoutTx = createDisputePayoutTx(trade, dispute, disputeResult, false); // can be null if already published or we don't have receiver's multisig hex
|
||||||
|
|
||||||
// persist result in dispute's chat message
|
// persist result in dispute's chat message once
|
||||||
|
boolean resending = disputeResult.getChatMessage() != null;
|
||||||
|
if (!resending) {
|
||||||
ChatMessage chatMessage = new ChatMessage(
|
ChatMessage chatMessage = new ChatMessage(
|
||||||
getSupportType(),
|
getSupportType(),
|
||||||
dispute.getTradeId(),
|
dispute.getTradeId(),
|
||||||
|
@ -713,12 +714,13 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
p2PService.getAddress());
|
p2PService.getAddress());
|
||||||
disputeResult.setChatMessage(chatMessage);
|
disputeResult.setChatMessage(chatMessage);
|
||||||
dispute.addAndPersistChatMessage(chatMessage);
|
dispute.addAndPersistChatMessage(chatMessage);
|
||||||
|
}
|
||||||
|
|
||||||
// create dispute closed message
|
// create dispute closed message
|
||||||
TradingPeer receiver = trade.getTradingPeer(dispute.getTraderPubKeyRing());
|
TradingPeer receiver = trade.getTradingPeer(dispute.getTraderPubKeyRing());
|
||||||
String unsignedPayoutTxHex = payoutTx == null ? null : payoutTx.getTxSet().getMultisigTxHex();
|
String unsignedPayoutTxHex = payoutTx == null ? null : payoutTx.getTxSet().getMultisigTxHex();
|
||||||
TradingPeer receiverPeer = receiver == trade.getBuyer() ? trade.getSeller() : trade.getBuyer();
|
TradingPeer receiverPeer = receiver == trade.getBuyer() ? trade.getSeller() : trade.getBuyer();
|
||||||
boolean deferPublishPayout = unsignedPayoutTxHex != null && receiverPeer.getUpdatedMultisigHex() != null && trade.getDisputeState().ordinal() >= Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG.ordinal() ;
|
boolean deferPublishPayout = !resending && unsignedPayoutTxHex != null && receiverPeer.getUpdatedMultisigHex() != null && trade.getDisputeState().ordinal() >= Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG.ordinal() ;
|
||||||
DisputeClosedMessage disputeClosedMessage = new DisputeClosedMessage(disputeResult,
|
DisputeClosedMessage disputeClosedMessage = new DisputeClosedMessage(disputeResult,
|
||||||
p2PService.getAddress(),
|
p2PService.getAddress(),
|
||||||
UUID.randomUUID().toString(),
|
UUID.randomUUID().toString(),
|
||||||
|
@ -731,7 +733,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
log.info("Send {} to trader {}. tradeId={}, {}.uid={}, chatMessage.uid={}",
|
log.info("Send {} to trader {}. tradeId={}, {}.uid={}, chatMessage.uid={}",
|
||||||
disputeClosedMessage.getClass().getSimpleName(), receiver.getNodeAddress(),
|
disputeClosedMessage.getClass().getSimpleName(), receiver.getNodeAddress(),
|
||||||
disputeClosedMessage.getClass().getSimpleName(), disputeClosedMessage.getTradeId(),
|
disputeClosedMessage.getClass().getSimpleName(), disputeClosedMessage.getTradeId(),
|
||||||
disputeClosedMessage.getUid(), chatMessage.getUid());
|
disputeClosedMessage.getUid(), disputeResult.getChatMessage().getUid());
|
||||||
mailboxMessageService.sendEncryptedMailboxMessage(receiver.getNodeAddress(),
|
mailboxMessageService.sendEncryptedMailboxMessage(receiver.getNodeAddress(),
|
||||||
dispute.getTraderPubKeyRing(),
|
dispute.getTraderPubKeyRing(),
|
||||||
disputeClosedMessage,
|
disputeClosedMessage,
|
||||||
|
@ -742,11 +744,11 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
"chatMessage.uid={}",
|
"chatMessage.uid={}",
|
||||||
disputeClosedMessage.getClass().getSimpleName(), receiver.getNodeAddress(),
|
disputeClosedMessage.getClass().getSimpleName(), receiver.getNodeAddress(),
|
||||||
disputeClosedMessage.getTradeId(), disputeClosedMessage.getUid(),
|
disputeClosedMessage.getTradeId(), disputeClosedMessage.getUid(),
|
||||||
chatMessage.getUid());
|
disputeResult.getChatMessage().getUid());
|
||||||
|
|
||||||
// We use the chatMessage wrapped inside the DisputeClosedMessage for
|
// We use the chatMessage wrapped inside the DisputeClosedMessage for
|
||||||
// the state, as that is displayed to the user and we only persist that msg
|
// the state, as that is displayed to the user and we only persist that msg
|
||||||
chatMessage.setArrived(true);
|
disputeResult.getChatMessage().setArrived(true);
|
||||||
trade.setDisputeStateIfProgress(Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG);
|
trade.setDisputeStateIfProgress(Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG);
|
||||||
trade.syncWalletNormallyForMs(30000);
|
trade.syncWalletNormallyForMs(30000);
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
|
@ -759,11 +761,11 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
"chatMessage.uid={}",
|
"chatMessage.uid={}",
|
||||||
disputeClosedMessage.getClass().getSimpleName(), receiver.getNodeAddress(),
|
disputeClosedMessage.getClass().getSimpleName(), receiver.getNodeAddress(),
|
||||||
disputeClosedMessage.getTradeId(), disputeClosedMessage.getUid(),
|
disputeClosedMessage.getTradeId(), disputeClosedMessage.getUid(),
|
||||||
chatMessage.getUid());
|
disputeResult.getChatMessage().getUid());
|
||||||
|
|
||||||
// We use the chatMessage wrapped inside the DisputeClosedMessage for
|
// We use the chatMessage wrapped inside the DisputeClosedMessage for
|
||||||
// the state, as that is displayed to the user and we only persist that msg
|
// the state, as that is displayed to the user and we only persist that msg
|
||||||
chatMessage.setStoredInMailbox(true);
|
disputeResult.getChatMessage().setStoredInMailbox(true);
|
||||||
Trade trade = tradeManager.getTrade(dispute.getTradeId());
|
Trade trade = tradeManager.getTrade(dispute.getTradeId());
|
||||||
trade.setDisputeStateIfProgress(Trade.DisputeState.ARBITRATOR_STORED_IN_MAILBOX_DISPUTE_CLOSED_MSG);
|
trade.setDisputeStateIfProgress(Trade.DisputeState.ARBITRATOR_STORED_IN_MAILBOX_DISPUTE_CLOSED_MSG);
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
|
@ -776,11 +778,11 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
"chatMessage.uid={}, errorMessage={}",
|
"chatMessage.uid={}, errorMessage={}",
|
||||||
disputeClosedMessage.getClass().getSimpleName(), receiver.getNodeAddress(),
|
disputeClosedMessage.getClass().getSimpleName(), receiver.getNodeAddress(),
|
||||||
disputeClosedMessage.getTradeId(), disputeClosedMessage.getUid(),
|
disputeClosedMessage.getTradeId(), disputeClosedMessage.getUid(),
|
||||||
chatMessage.getUid(), errorMessage);
|
disputeResult.getChatMessage().getUid(), errorMessage);
|
||||||
|
|
||||||
// We use the chatMessage wrapped inside the DisputeClosedMessage for
|
// We use the chatMessage wrapped inside the DisputeClosedMessage for
|
||||||
// the state, as that is displayed to the user and we only persist that msg
|
// the state, as that is displayed to the user and we only persist that msg
|
||||||
chatMessage.setSendMessageError(errorMessage);
|
disputeResult.getChatMessage().setSendMessageError(errorMessage);
|
||||||
trade.setDisputeStateIfProgress(Trade.DisputeState.ARBITRATOR_SEND_FAILED_DISPUTE_CLOSED_MSG);
|
trade.setDisputeStateIfProgress(Trade.DisputeState.ARBITRATOR_SEND_FAILED_DISPUTE_CLOSED_MSG);
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
faultHandler.handleFault(errorMessage, new RuntimeException(errorMessage));
|
faultHandler.handleFault(errorMessage, new RuntimeException(errorMessage));
|
||||||
|
@ -914,7 +916,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAgent(Dispute dispute) {
|
private boolean isAgent(Dispute dispute) {
|
||||||
return pubKeyRing.equals(dispute.getAgentPubKeyRing());
|
return keyRing.getPubKeyRing().equals(dispute.getAgentPubKeyRing());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<Dispute> findDispute(Dispute dispute) {
|
private Optional<Dispute> findDispute(Dispute dispute) {
|
||||||
|
@ -987,7 +989,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
ChatMessage mediatorsDisputeClosedMessage = new ChatMessage(
|
ChatMessage mediatorsDisputeClosedMessage = new ChatMessage(
|
||||||
getSupportType(),
|
getSupportType(),
|
||||||
dispute.getTradeId(),
|
dispute.getTradeId(),
|
||||||
pubKeyRing.hashCode(),
|
keyRing.getPubKeyRing().hashCode(),
|
||||||
false,
|
false,
|
||||||
mediatorsDisputeResult,
|
mediatorsDisputeResult,
|
||||||
p2PService.getAddress());
|
p2PService.getAddress());
|
||||||
|
@ -1074,7 +1076,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||||
ChatMessage priceInfoMessage = new ChatMessage(
|
ChatMessage priceInfoMessage = new ChatMessage(
|
||||||
getSupportType(),
|
getSupportType(),
|
||||||
dispute.getTradeId(),
|
dispute.getTradeId(),
|
||||||
pubKeyRing.hashCode(),
|
keyRing.getPubKeyRing().hashCode(),
|
||||||
false,
|
false,
|
||||||
priceInfoText,
|
priceInfoText,
|
||||||
p2PService.getAddress());
|
p2PService.getAddress());
|
||||||
|
|
|
@ -88,6 +88,7 @@ public class DisputeSummaryVerification {
|
||||||
throw new IllegalArgumentException(Res.get("support.sigCheck.popup.failed"));
|
throw new IllegalArgumentException(Res.get("support.sigCheck.popup.failed"));
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
throw new IllegalArgumentException(Res.get("support.sigCheck.popup.invalidFormat"));
|
throw new IllegalArgumentException(Res.get("support.sigCheck.popup.invalidFormat"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,7 +211,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
||||||
Dispute dispute = disputeOptional.get();
|
Dispute dispute = disputeOptional.get();
|
||||||
|
|
||||||
// verify that arbitrator does not get DisputeClosedMessage
|
// verify that arbitrator does not get DisputeClosedMessage
|
||||||
if (pubKeyRing.equals(dispute.getAgentPubKeyRing())) {
|
if (keyRing.getPubKeyRing().equals(dispute.getAgentPubKeyRing())) {
|
||||||
log.error("Arbitrator received disputeResultMessage. That should never happen.");
|
log.error("Arbitrator received disputeResultMessage. That should never happen.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -225,8 +225,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
||||||
}
|
}
|
||||||
dispute.setIsClosed();
|
dispute.setIsClosed();
|
||||||
if (dispute.disputeResultProperty().get() != null) {
|
if (dispute.disputeResultProperty().get() != null) {
|
||||||
log.warn("We already got a dispute result. That should only happen if a dispute needs to be closed " +
|
log.info("We already got a dispute result, indicating the message was resent after updating multisig info. TradeId = " + tradeId);
|
||||||
"again because the first close did not succeed. TradeId = " + tradeId);
|
|
||||||
}
|
}
|
||||||
dispute.setDisputeResult(disputeResult);
|
dispute.setDisputeResult(disputeResult);
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ import bisq.core.trade.protocol.tasks.TradeTask;
|
||||||
import bisq.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness;
|
import bisq.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness;
|
||||||
import bisq.core.trade.protocol.FluentProtocol.Condition;
|
import bisq.core.trade.protocol.FluentProtocol.Condition;
|
||||||
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
import bisq.core.trade.protocol.tasks.ApplyFilter;
|
||||||
|
import bisq.core.trade.protocol.tasks.ResendDisputeClosedMessageWithPayout;
|
||||||
import bisq.core.trade.protocol.tasks.MaybeSendSignContractRequest;
|
import bisq.core.trade.protocol.tasks.MaybeSendSignContractRequest;
|
||||||
import bisq.core.trade.protocol.tasks.ProcessDepositResponse;
|
import bisq.core.trade.protocol.tasks.ProcessDepositResponse;
|
||||||
import bisq.core.trade.protocol.tasks.ProcessDepositsConfirmedMessage;
|
import bisq.core.trade.protocol.tasks.ProcessDepositsConfirmedMessage;
|
||||||
|
@ -73,6 +74,7 @@ import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
|
@ -162,6 +164,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
|
|
||||||
// TODO (woodser): this method only necessary because isPubKeyValid not called with sender argument, so it's validated before
|
// TODO (woodser): this method only necessary because isPubKeyValid not called with sender argument, so it's validated before
|
||||||
private void handleMailboxCollectionSkipValidation(Collection<DecryptedMessageWithPubKey> collection) {
|
private void handleMailboxCollectionSkipValidation(Collection<DecryptedMessageWithPubKey> collection) {
|
||||||
|
log.warn("TradeProtocol.handleMailboxCollectionSkipValidation");
|
||||||
collection.stream()
|
collection.stream()
|
||||||
.map(DecryptedMessageWithPubKey::getNetworkEnvelope)
|
.map(DecryptedMessageWithPubKey::getNetworkEnvelope)
|
||||||
.filter(this::isMyMessage)
|
.filter(this::isMyMessage)
|
||||||
|
@ -181,8 +184,9 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
.forEach(this::handleMailboxMessage);
|
.forEach(this::handleMailboxMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MailboxMessageComparator implements Comparator<MailboxMessage> {
|
public static class MailboxMessageComparator implements Comparator<MailboxMessage> {
|
||||||
private static List<Class<? extends MailboxMessage>> messageOrder = Arrays.asList(
|
private static List<Class<? extends MailboxMessage>> messageOrder = Arrays.asList(
|
||||||
|
AckMessage.class,
|
||||||
DepositsConfirmedMessage.class,
|
DepositsConfirmedMessage.class,
|
||||||
PaymentSentMessage.class,
|
PaymentSentMessage.class,
|
||||||
PaymentReceivedMessage.class,
|
PaymentReceivedMessage.class,
|
||||||
|
@ -397,7 +401,8 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
.from(sender))
|
.from(sender))
|
||||||
.setup(tasks(
|
.setup(tasks(
|
||||||
ProcessDepositsConfirmedMessage.class,
|
ProcessDepositsConfirmedMessage.class,
|
||||||
VerifyPeersAccountAgeWitness.class)
|
VerifyPeersAccountAgeWitness.class,
|
||||||
|
ResendDisputeClosedMessageWithPayout.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
handleTaskRunnerSuccess(sender, response);
|
handleTaskRunnerSuccess(sender, response);
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Haveno.
|
||||||
|
*
|
||||||
|
* Haveno is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* Haveno is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with Haveno. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bisq.core.trade.protocol.tasks;
|
||||||
|
|
||||||
|
|
||||||
|
import bisq.common.taskrunner.TaskRunner;
|
||||||
|
import bisq.core.support.dispute.Dispute;
|
||||||
|
import bisq.core.trade.HavenoUtils;
|
||||||
|
import bisq.core.trade.Trade;
|
||||||
|
import bisq.core.trade.messages.DepositsConfirmedMessage;
|
||||||
|
import bisq.core.trade.protocol.TradingPeer;
|
||||||
|
import bisq.core.util.Validator;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class ResendDisputeClosedMessageWithPayout extends TradeTask {
|
||||||
|
|
||||||
|
@SuppressWarnings({"unused"})
|
||||||
|
public ResendDisputeClosedMessageWithPayout(TaskRunner taskHandler, Trade trade) {
|
||||||
|
super(taskHandler, trade);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void run() {
|
||||||
|
try {
|
||||||
|
runInterceptHook();
|
||||||
|
|
||||||
|
// get peer
|
||||||
|
DepositsConfirmedMessage request = (DepositsConfirmedMessage) processModel.getTradeMessage();
|
||||||
|
checkNotNull(request);
|
||||||
|
Validator.checkTradeId(processModel.getOfferId(), request);
|
||||||
|
TradingPeer sender = trade.getTradingPeer(request.getPubKeyRing());
|
||||||
|
if (sender == null) throw new RuntimeException("Pub key ring is not from arbitrator, buyer, or seller");
|
||||||
|
|
||||||
|
// arbitrator resends DisputeClosedMessage with payout tx when updated multisig info received
|
||||||
|
boolean ticketClosed = false;
|
||||||
|
if (!trade.isPayoutPublished() && trade.isArbitrator()) {
|
||||||
|
List<Dispute> disputes = trade.getDisputes();
|
||||||
|
for (Dispute dispute : disputes) {
|
||||||
|
if (!dispute.isClosed()) continue; // dispute must be closed
|
||||||
|
if (sender.getPubKeyRing().equals(dispute.getTraderPubKeyRing())) {
|
||||||
|
HavenoUtils.arbitrationManager.closeDisputeTicket(dispute.getDisputeResultProperty().get(), dispute, dispute.getDisputeResultProperty().get().summaryNotesProperty().get(), null, () -> {
|
||||||
|
completeAux();
|
||||||
|
}, (errMessage, err) -> {
|
||||||
|
err.printStackTrace();
|
||||||
|
failed(err);
|
||||||
|
});
|
||||||
|
ticketClosed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// complete if not waiting for result
|
||||||
|
if (!ticketClosed) completeAux();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
failed(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void completeAux() {
|
||||||
|
processModel.getTradeManager().requestPersistence();
|
||||||
|
complete();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue