mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-12-22 19:49:32 +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();
|
||||
|
||||
arbitratorManager.onAllServicesInitialized();
|
||||
mediatorManager.onAllServicesInitialized();
|
||||
refundAgentManager.onAllServicesInitialized();
|
||||
|
||||
tradeManager.onAllServicesInitialized();
|
||||
arbitrationManager.onAllServicesInitialized();
|
||||
mediationManager.onAllServicesInitialized();
|
||||
|
@ -192,10 +196,6 @@ public class DomainInitialisation {
|
|||
|
||||
walletAppSetup.setRejectedTxErrorMessageHandler(rejectedTxErrorMessageHandler, openOfferManager, tradeManager);
|
||||
|
||||
arbitratorManager.onAllServicesInitialized();
|
||||
mediatorManager.onAllServicesInitialized();
|
||||
refundAgentManager.onAllServicesInitialized();
|
||||
|
||||
privateNotificationManager.privateNotificationProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (displayPrivateNotificationHandler != null)
|
||||
displayPrivateNotificationHandler.accept(newValue);
|
||||
|
|
|
@ -22,13 +22,15 @@ import bisq.core.api.CoreNotificationService;
|
|||
import bisq.core.locale.Res;
|
||||
import bisq.core.support.messages.ChatMessage;
|
||||
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.AckMessageSourceType;
|
||||
import bisq.network.p2p.DecryptedMessageWithPubKey;
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
import bisq.network.p2p.P2PService;
|
||||
import bisq.network.p2p.SendMailboxMessageListener;
|
||||
import bisq.network.p2p.mailbox.MailboxMessage;
|
||||
import bisq.network.p2p.mailbox.MailboxMessageService;
|
||||
|
||||
import bisq.common.Timer;
|
||||
|
@ -36,6 +38,7 @@ import bisq.common.UserThread;
|
|||
import bisq.common.crypto.PubKeyRing;
|
||||
import bisq.common.proto.network.NetworkEnvelope;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -322,9 +325,27 @@ public abstract class SupportManager {
|
|||
|
||||
private void applyMessages() {
|
||||
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();
|
||||
decryptedMailboxMessageWithPubKeys.forEach(decryptedMessageWithPubKey -> applyMailboxMessage(decryptedMessageWithPubKey));
|
||||
decryptedMailboxMessageWithPubKeys.clear();
|
||||
}
|
||||
}
|
||||
|
@ -351,4 +372,22 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
protected final TradeManager tradeManager;
|
||||
protected final ClosedTradableManager closedTradableManager;
|
||||
protected final OpenOfferManager openOfferManager;
|
||||
protected final PubKeyRing pubKeyRing;
|
||||
protected final KeyRing keyRing;
|
||||
protected final DisputeListService<T> disputeListService;
|
||||
private final Config config;
|
||||
private final PriceFeedService priceFeedService;
|
||||
|
@ -105,9 +105,6 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
@Getter
|
||||
protected final ObservableList<TradeDataValidation.ValidationException> validationExceptions =
|
||||
FXCollections.observableArrayList();
|
||||
@Getter
|
||||
private final KeyPair signatureKeyPair;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
|
@ -132,18 +129,20 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
this.tradeManager = tradeManager;
|
||||
this.closedTradableManager = closedTradableManager;
|
||||
this.openOfferManager = openOfferManager;
|
||||
this.pubKeyRing = keyRing.getPubKeyRing();
|
||||
signatureKeyPair = keyRing.getSignatureKeyPair();
|
||||
this.keyRing = keyRing;
|
||||
this.disputeListService = disputeListService;
|
||||
this.config = config;
|
||||
this.priceFeedService = priceFeedService;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Implement template methods
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public KeyPair getSignatureKeyPair() {
|
||||
return keyRing.getSignatureKeyPair();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestPersistence() {
|
||||
disputeListService.requestPersistence();
|
||||
|
@ -204,7 +203,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
// 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 NodeAddress getAgentNodeAddress(Dispute dispute);
|
||||
|
@ -292,7 +291,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
}
|
||||
|
||||
public boolean isTrader(Dispute dispute) {
|
||||
return pubKeyRing.equals(dispute.getTraderPubKeyRing());
|
||||
return keyRing.getPubKeyRing().equals(dispute.getTraderPubKeyRing());
|
||||
}
|
||||
|
||||
public Optional<Dispute> findOwnDispute(String tradeId) {
|
||||
|
@ -352,7 +351,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
ChatMessage chatMessage = new ChatMessage(
|
||||
getSupportType(),
|
||||
dispute.getTradeId(),
|
||||
pubKeyRing.hashCode(),
|
||||
keyRing.getPubKeyRing().hashCode(),
|
||||
false,
|
||||
Res.get("support.systemMsg", sysMsg),
|
||||
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
|
||||
// the state, as that is displayed to the user and we only persist that msg
|
||||
chatMessage.setArrived(true);
|
||||
trade.setDisputeState(Trade.DisputeState.DISPUTE_OPENED);
|
||||
trade.setDisputeStateIfProgress(Trade.DisputeState.DISPUTE_OPENED);
|
||||
requestPersistence();
|
||||
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
|
||||
// the state, as that is displayed to the user and we only persist that msg
|
||||
chatMessage.setStoredInMailbox(true);
|
||||
trade.setDisputeState(Trade.DisputeState.DISPUTE_OPENED);
|
||||
trade.setDisputeStateIfProgress(Trade.DisputeState.DISPUTE_OPENED);
|
||||
requestPersistence();
|
||||
resultHandler.handleResult();
|
||||
}
|
||||
|
@ -507,7 +506,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
Optional<Dispute> storedDisputeOptional = findDispute(dispute);
|
||||
if (!storedDisputeOptional.isPresent()) {
|
||||
disputeList.add(dispute);
|
||||
trade.setDisputeState(Trade.DisputeState.DISPUTE_OPENED);
|
||||
trade.setDisputeStateIfProgress(Trade.DisputeState.DISPUTE_OPENED);
|
||||
|
||||
// send dispute opened message to peer if arbitrator
|
||||
if (trade.isArbitrator()) sendDisputeOpenedMessageToPeer(dispute, contract, dispute.isDisputeOpenerIsBuyer() ? contract.getSellerPubKeyRing() : contract.getBuyerPubKeyRing(), trade.getSelf().getUpdatedMultisigHex());
|
||||
|
@ -703,22 +702,25 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
// 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
|
||||
|
||||
// persist result in dispute's chat message
|
||||
ChatMessage chatMessage = new ChatMessage(
|
||||
getSupportType(),
|
||||
dispute.getTradeId(),
|
||||
dispute.getTraderPubKeyRing().hashCode(),
|
||||
false,
|
||||
summaryText,
|
||||
p2PService.getAddress());
|
||||
disputeResult.setChatMessage(chatMessage);
|
||||
dispute.addAndPersistChatMessage(chatMessage);
|
||||
// persist result in dispute's chat message once
|
||||
boolean resending = disputeResult.getChatMessage() != null;
|
||||
if (!resending) {
|
||||
ChatMessage chatMessage = new ChatMessage(
|
||||
getSupportType(),
|
||||
dispute.getTradeId(),
|
||||
dispute.getTraderPubKeyRing().hashCode(),
|
||||
false,
|
||||
summaryText,
|
||||
p2PService.getAddress());
|
||||
disputeResult.setChatMessage(chatMessage);
|
||||
dispute.addAndPersistChatMessage(chatMessage);
|
||||
}
|
||||
|
||||
// create dispute closed message
|
||||
TradingPeer receiver = trade.getTradingPeer(dispute.getTraderPubKeyRing());
|
||||
String unsignedPayoutTxHex = payoutTx == null ? null : payoutTx.getTxSet().getMultisigTxHex();
|
||||
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,
|
||||
p2PService.getAddress(),
|
||||
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={}",
|
||||
disputeClosedMessage.getClass().getSimpleName(), receiver.getNodeAddress(),
|
||||
disputeClosedMessage.getClass().getSimpleName(), disputeClosedMessage.getTradeId(),
|
||||
disputeClosedMessage.getUid(), chatMessage.getUid());
|
||||
disputeClosedMessage.getUid(), disputeResult.getChatMessage().getUid());
|
||||
mailboxMessageService.sendEncryptedMailboxMessage(receiver.getNodeAddress(),
|
||||
dispute.getTraderPubKeyRing(),
|
||||
disputeClosedMessage,
|
||||
|
@ -742,11 +744,11 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
"chatMessage.uid={}",
|
||||
disputeClosedMessage.getClass().getSimpleName(), receiver.getNodeAddress(),
|
||||
disputeClosedMessage.getTradeId(), disputeClosedMessage.getUid(),
|
||||
chatMessage.getUid());
|
||||
disputeResult.getChatMessage().getUid());
|
||||
|
||||
// We use the chatMessage wrapped inside the DisputeClosedMessage for
|
||||
// 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.syncWalletNormallyForMs(30000);
|
||||
requestPersistence();
|
||||
|
@ -759,11 +761,11 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
"chatMessage.uid={}",
|
||||
disputeClosedMessage.getClass().getSimpleName(), receiver.getNodeAddress(),
|
||||
disputeClosedMessage.getTradeId(), disputeClosedMessage.getUid(),
|
||||
chatMessage.getUid());
|
||||
disputeResult.getChatMessage().getUid());
|
||||
|
||||
// We use the chatMessage wrapped inside the DisputeClosedMessage for
|
||||
// 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.setDisputeStateIfProgress(Trade.DisputeState.ARBITRATOR_STORED_IN_MAILBOX_DISPUTE_CLOSED_MSG);
|
||||
requestPersistence();
|
||||
|
@ -776,11 +778,11 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
"chatMessage.uid={}, errorMessage={}",
|
||||
disputeClosedMessage.getClass().getSimpleName(), receiver.getNodeAddress(),
|
||||
disputeClosedMessage.getTradeId(), disputeClosedMessage.getUid(),
|
||||
chatMessage.getUid(), errorMessage);
|
||||
disputeResult.getChatMessage().getUid(), errorMessage);
|
||||
|
||||
// We use the chatMessage wrapped inside the DisputeClosedMessage for
|
||||
// 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);
|
||||
requestPersistence();
|
||||
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) {
|
||||
return pubKeyRing.equals(dispute.getAgentPubKeyRing());
|
||||
return keyRing.getPubKeyRing().equals(dispute.getAgentPubKeyRing());
|
||||
}
|
||||
|
||||
private Optional<Dispute> findDispute(Dispute dispute) {
|
||||
|
@ -987,7 +989,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
ChatMessage mediatorsDisputeClosedMessage = new ChatMessage(
|
||||
getSupportType(),
|
||||
dispute.getTradeId(),
|
||||
pubKeyRing.hashCode(),
|
||||
keyRing.getPubKeyRing().hashCode(),
|
||||
false,
|
||||
mediatorsDisputeResult,
|
||||
p2PService.getAddress());
|
||||
|
@ -1074,7 +1076,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
ChatMessage priceInfoMessage = new ChatMessage(
|
||||
getSupportType(),
|
||||
dispute.getTradeId(),
|
||||
pubKeyRing.hashCode(),
|
||||
keyRing.getPubKeyRing().hashCode(),
|
||||
false,
|
||||
priceInfoText,
|
||||
p2PService.getAddress());
|
||||
|
|
|
@ -88,6 +88,7 @@ public class DisputeSummaryVerification {
|
|||
throw new IllegalArgumentException(Res.get("support.sigCheck.popup.failed"));
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new IllegalArgumentException(Res.get("support.sigCheck.popup.invalidFormat"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
Dispute dispute = disputeOptional.get();
|
||||
|
||||
// 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.");
|
||||
return;
|
||||
}
|
||||
|
@ -225,8 +225,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
|||
}
|
||||
dispute.setIsClosed();
|
||||
if (dispute.disputeResultProperty().get() != null) {
|
||||
log.warn("We already got a dispute result. That should only happen if a dispute needs to be closed " +
|
||||
"again because the first close did not succeed. TradeId = " + tradeId);
|
||||
log.info("We already got a dispute result, indicating the message was resent after updating multisig info. TradeId = " + tradeId);
|
||||
}
|
||||
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.FluentProtocol.Condition;
|
||||
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.ProcessDepositResponse;
|
||||
import bisq.core.trade.protocol.tasks.ProcessDepositsConfirmedMessage;
|
||||
|
@ -73,6 +74,7 @@ import java.util.Comparator;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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
|
||||
private void handleMailboxCollectionSkipValidation(Collection<DecryptedMessageWithPubKey> collection) {
|
||||
log.warn("TradeProtocol.handleMailboxCollectionSkipValidation");
|
||||
collection.stream()
|
||||
.map(DecryptedMessageWithPubKey::getNetworkEnvelope)
|
||||
.filter(this::isMyMessage)
|
||||
|
@ -181,8 +184,9 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
|||
.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(
|
||||
AckMessage.class,
|
||||
DepositsConfirmedMessage.class,
|
||||
PaymentSentMessage.class,
|
||||
PaymentReceivedMessage.class,
|
||||
|
@ -397,7 +401,8 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
|||
.from(sender))
|
||||
.setup(tasks(
|
||||
ProcessDepositsConfirmedMessage.class,
|
||||
VerifyPeersAccountAgeWitness.class)
|
||||
VerifyPeersAccountAgeWitness.class,
|
||||
ResendDisputeClosedMessageWithPayout.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
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