mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-12-25 15:29:23 -05:00
arbitrator sends original unsigned payout tx if published
synchronize on trade when processing dispute messages
This commit is contained in:
parent
17ac09fa4d
commit
6dca11f471
@ -36,7 +36,6 @@ import java.util.List;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import monero.wallet.model.MoneroTxWallet;
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static java.lang.String.format;
|
import static java.lang.String.format;
|
||||||
@ -171,25 +170,25 @@ public class CoreDisputesService {
|
|||||||
applyPayoutAmountsToDisputeResult(payout, winningDispute, disputeResult, customWinnerAmount);
|
applyPayoutAmountsToDisputeResult(payout, winningDispute, disputeResult, customWinnerAmount);
|
||||||
|
|
||||||
// create dispute payout tx
|
// create dispute payout tx
|
||||||
MoneroTxWallet disputePayoutTx = arbitrationManager.createDisputePayoutTx(trade, winningDispute.getContract(), disputeResult, false);
|
trade.getProcessModel().setUnsignedPayoutTx(arbitrationManager.createDisputePayoutTx(trade, winningDispute.getContract(), disputeResult, false));
|
||||||
|
|
||||||
// close winning dispute ticket
|
// close winning dispute ticket
|
||||||
closeDisputeTicket(arbitrationManager, winningDispute, disputeResult, disputePayoutTx, () -> {
|
closeDisputeTicket(arbitrationManager, winningDispute, disputeResult, () -> {
|
||||||
arbitrationManager.requestPersistence();
|
arbitrationManager.requestPersistence();
|
||||||
}, (errMessage, err) -> {
|
}, (errMessage, err) -> {
|
||||||
throw new IllegalStateException(errMessage, err);
|
throw new IllegalStateException(errMessage, err);
|
||||||
});
|
});
|
||||||
|
|
||||||
// close loser's dispute ticket
|
// close loser's dispute ticket
|
||||||
var peersDisputeOptional = arbitrationManager.getDisputesAsObservableList().stream()
|
var loserDisputeOptional = arbitrationManager.getDisputesAsObservableList().stream()
|
||||||
.filter(d -> tradeId.equals(d.getTradeId()) && winningDispute.getTraderId() != d.getTraderId())
|
.filter(d -> tradeId.equals(d.getTradeId()) && winningDispute.getTraderId() != d.getTraderId())
|
||||||
.findFirst();
|
.findFirst();
|
||||||
if (!peersDisputeOptional.isPresent()) throw new IllegalStateException("could not find peer dispute");
|
if (!loserDisputeOptional.isPresent()) throw new IllegalStateException("could not find peer dispute");
|
||||||
var peerDispute = peersDisputeOptional.get();
|
var loserDispute = loserDisputeOptional.get();
|
||||||
var peerDisputeResult = createDisputeResult(peerDispute, winner, reason, summaryNotes, closeDate);
|
var loserDisputeResult = createDisputeResult(loserDispute, winner, reason, summaryNotes, closeDate);
|
||||||
peerDisputeResult.setBuyerPayoutAmount(disputeResult.getBuyerPayoutAmount());
|
loserDisputeResult.setBuyerPayoutAmount(disputeResult.getBuyerPayoutAmount());
|
||||||
peerDisputeResult.setSellerPayoutAmount(disputeResult.getSellerPayoutAmount());
|
loserDisputeResult.setSellerPayoutAmount(disputeResult.getSellerPayoutAmount());
|
||||||
closeDisputeTicket(arbitrationManager, peerDispute, peerDisputeResult, disputePayoutTx, () -> {
|
closeDisputeTicket(arbitrationManager, loserDispute, loserDisputeResult, () -> {
|
||||||
arbitrationManager.requestPersistence();
|
arbitrationManager.requestPersistence();
|
||||||
}, (errMessage, err) -> {
|
}, (errMessage, err) -> {
|
||||||
throw new IllegalStateException(errMessage, err);
|
throw new IllegalStateException(errMessage, err);
|
||||||
@ -248,7 +247,7 @@ public class CoreDisputesService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closeDisputeTicket(DisputeManager disputeManager, Dispute dispute, DisputeResult disputeResult, MoneroTxWallet payoutTx, ResultHandler resultHandler, FaultHandler faultHandler) {
|
public void closeDisputeTicket(DisputeManager disputeManager, Dispute dispute, DisputeResult disputeResult, ResultHandler resultHandler, FaultHandler faultHandler) {
|
||||||
DisputeResult.Reason reason = disputeResult.getReason();
|
DisputeResult.Reason reason = disputeResult.getReason();
|
||||||
|
|
||||||
String role = Res.get("shared.arbitrator");
|
String role = Res.get("shared.arbitrator");
|
||||||
@ -279,7 +278,7 @@ public class CoreDisputesService {
|
|||||||
String summaryText = DisputeSummaryVerification.signAndApply(disputeManager, disputeResult, textToSign);
|
String summaryText = DisputeSummaryVerification.signAndApply(disputeManager, disputeResult, textToSign);
|
||||||
summaryText += Res.get("disputeSummaryWindow.close.nextStepsForRefundAgentArbitration");
|
summaryText += Res.get("disputeSummaryWindow.close.nextStepsForRefundAgentArbitration");
|
||||||
|
|
||||||
disputeManager.closeDisputeTicket(disputeResult, dispute, summaryText, payoutTx, () -> {
|
disputeManager.closeDisputeTicket(disputeResult, dispute, summaryText, () -> {
|
||||||
dispute.setDisputeResult(disputeResult);
|
dispute.setDisputeResult(disputeResult);
|
||||||
dispute.setIsClosed();
|
dispute.setIsClosed();
|
||||||
resultHandler.handleResult();
|
resultHandler.handleResult();
|
||||||
|
@ -443,7 +443,14 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||||||
Dispute dispute = message.getDispute();
|
Dispute dispute = message.getDispute();
|
||||||
log.info("{}.onDisputeOpenedMessage() with trade {}, dispute {}", getClass().getSimpleName(), dispute.getTradeId(), dispute.getId());
|
log.info("{}.onDisputeOpenedMessage() with trade {}, dispute {}", getClass().getSimpleName(), dispute.getTradeId(), dispute.getId());
|
||||||
|
|
||||||
Trade trade = null;
|
// get trade
|
||||||
|
Trade trade = tradeManager.getTrade(dispute.getTradeId());
|
||||||
|
if (trade == null) {
|
||||||
|
log.warn("Dispute trade {} does not exist", dispute.getTradeId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (trade) {
|
||||||
String errorMessage = null;
|
String errorMessage = null;
|
||||||
PubKeyRing senderPubKeyRing = null;
|
PubKeyRing senderPubKeyRing = null;
|
||||||
try {
|
try {
|
||||||
@ -470,13 +477,6 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get trade
|
|
||||||
trade = tradeManager.getTrade(dispute.getTradeId());
|
|
||||||
if (trade == null) {
|
|
||||||
log.warn("Dispute trade {} does not exist", dispute.getTradeId());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get sender
|
// get sender
|
||||||
senderPubKeyRing = trade.isArbitrator() ? (dispute.isDisputeOpenerIsBuyer() ? contract.getBuyerPubKeyRing() : contract.getSellerPubKeyRing()) : trade.getArbitrator().getPubKeyRing();
|
senderPubKeyRing = trade.isArbitrator() ? (dispute.isDisputeOpenerIsBuyer() ? contract.getBuyerPubKeyRing() : contract.getSellerPubKeyRing()) : trade.getArbitrator().getPubKeyRing();
|
||||||
TradePeer sender = trade.getTradePeer(senderPubKeyRing);
|
TradePeer sender = trade.getTradePeer(senderPubKeyRing);
|
||||||
@ -543,6 +543,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||||||
|
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// arbitrator sends dispute opened message to opener's peer
|
// arbitrator sends dispute opened message to opener's peer
|
||||||
private void sendDisputeOpenedMessageToPeer(Dispute disputeFromOpener,
|
private void sendDisputeOpenedMessageToPeer(Dispute disputeFromOpener,
|
||||||
@ -700,16 +701,13 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||||||
}
|
}
|
||||||
|
|
||||||
// arbitrator sends result to trader when their dispute is closed
|
// arbitrator sends result to trader when their dispute is closed
|
||||||
public void closeDisputeTicket(DisputeResult disputeResult, Dispute dispute, String summaryText, MoneroTxWallet payoutTx, ResultHandler resultHandler, FaultHandler faultHandler) {
|
public void closeDisputeTicket(DisputeResult disputeResult, Dispute dispute, String summaryText, ResultHandler resultHandler, FaultHandler faultHandler) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// get trade
|
// get trade
|
||||||
Trade trade = tradeManager.getTrade(dispute.getTradeId());
|
Trade trade = tradeManager.getTrade(dispute.getTradeId());
|
||||||
if (trade == null) throw new RuntimeException("Dispute trade " + dispute.getTradeId() + " does not exist");
|
if (trade == null) throw new RuntimeException("Dispute trade " + dispute.getTradeId() + " does not exist");
|
||||||
|
|
||||||
// create dispute payout tx if not given
|
|
||||||
if (payoutTx == null) payoutTx = createDisputePayoutTx(trade, dispute.getContract(), disputeResult, false); // can be null if already published or we don't have receiver's multisig hex
|
|
||||||
|
|
||||||
// persist result in dispute's chat message once
|
// persist result in dispute's chat message once
|
||||||
boolean resending = disputeResult.getChatMessage() != null;
|
boolean resending = disputeResult.getChatMessage() != null;
|
||||||
if (!resending) {
|
if (!resending) {
|
||||||
@ -724,9 +722,15 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||||||
dispute.addAndPersistChatMessage(chatMessage);
|
dispute.addAndPersistChatMessage(chatMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create dispute closed message
|
// create dispute payout tx if not published
|
||||||
TradePeer receiver = trade.getTradePeer(dispute.getTraderPubKeyRing());
|
TradePeer receiver = trade.getTradePeer(dispute.getTraderPubKeyRing());
|
||||||
String unsignedPayoutTxHex = payoutTx == null ? null : payoutTx.getTxSet().getMultisigTxHex();
|
if (!trade.isPayoutPublished() && receiver.getUpdatedMultisigHex() != null) {
|
||||||
|
trade.getProcessModel().setUnsignedPayoutTx(createDisputePayoutTx(trade, dispute.getContract(), disputeResult, false)); // can be null if we don't have receiver's multisig hex
|
||||||
|
}
|
||||||
|
|
||||||
|
// create dispute closed message
|
||||||
|
MoneroTxWallet unsignedPayoutTx = receiver.getUpdatedMultisigHex() == null ? null : trade.getProcessModel().getUnsignedPayoutTx();
|
||||||
|
String unsignedPayoutTxHex = unsignedPayoutTx == null ? null : unsignedPayoutTx.getTxSet().getMultisigTxHex();
|
||||||
TradePeer receiverPeer = receiver == trade.getBuyer() ? trade.getSeller() : trade.getBuyer();
|
TradePeer receiverPeer = receiver == trade.getBuyer() ? trade.getSeller() : trade.getBuyer();
|
||||||
boolean deferPublishPayout = !resending && 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,
|
||||||
@ -799,9 +803,9 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||||||
);
|
);
|
||||||
|
|
||||||
// save state
|
// save state
|
||||||
if (payoutTx != null) {
|
if (unsignedPayoutTx != null) {
|
||||||
trade.setPayoutTx(payoutTx);
|
trade.setPayoutTx(unsignedPayoutTx);
|
||||||
trade.setPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex());
|
trade.setPayoutTxHex(unsignedPayoutTx.getTxSet().getMultisigTxHex());
|
||||||
}
|
}
|
||||||
trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG);
|
trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG);
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
|
@ -169,6 +169,9 @@ public class ProcessModel implements Model, PersistablePayload {
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
transient private MoneroTxWallet depositTxXmr;
|
transient private MoneroTxWallet depositTxXmr;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
transient private MoneroTxWallet unsignedPayoutTx;
|
||||||
@Nullable
|
@Nullable
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
|
@ -58,7 +58,8 @@ public class ResendDisputeClosedMessageWithPayout extends TradeTask {
|
|||||||
for (Dispute dispute : disputes) {
|
for (Dispute dispute : disputes) {
|
||||||
if (!dispute.isClosed()) continue; // dispute must be closed
|
if (!dispute.isClosed()) continue; // dispute must be closed
|
||||||
if (sender.getPubKeyRing().equals(dispute.getTraderPubKeyRing())) {
|
if (sender.getPubKeyRing().equals(dispute.getTraderPubKeyRing())) {
|
||||||
HavenoUtils.arbitrationManager.closeDisputeTicket(dispute.getDisputeResultProperty().get(), dispute, dispute.getDisputeResultProperty().get().summaryNotesProperty().get(), null, () -> {
|
log.info("Arbitrator resending DisputeClosedMessage for trade {} after receiving updated multisig hex", trade.getId());
|
||||||
|
HavenoUtils.arbitrationManager.closeDisputeTicket(dispute.getDisputeResultProperty().get(), dispute, dispute.getDisputeResultProperty().get().summaryNotesProperty().get(), () -> {
|
||||||
completeAux();
|
completeAux();
|
||||||
}, (errMessage, err) -> {
|
}, (errMessage, err) -> {
|
||||||
err.printStackTrace();
|
err.printStackTrace();
|
||||||
|
@ -590,8 +590,13 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||||||
|
|
||||||
closeTicketButton.setOnAction(e -> {
|
closeTicketButton.setOnAction(e -> {
|
||||||
|
|
||||||
// get or create payout tx
|
// get or create dispute payout tx
|
||||||
MoneroTxWallet payoutTx = trade.isPayoutPublished() ? trade.getPayoutTx() : arbitrationManager.createDisputePayoutTx(trade, dispute.getContract(), disputeResult, false);
|
MoneroTxWallet payoutTx = null;
|
||||||
|
if (trade.isPayoutPublished()) payoutTx = trade.getPayoutTx();
|
||||||
|
else {
|
||||||
|
payoutTx = arbitrationManager.createDisputePayoutTx(trade, dispute.getContract(), disputeResult, false);
|
||||||
|
trade.getProcessModel().setUnsignedPayoutTx(payoutTx);
|
||||||
|
}
|
||||||
|
|
||||||
// show confirmation
|
// show confirmation
|
||||||
if (dispute.getSupportType() == SupportType.ARBITRATION &&
|
if (dispute.getSupportType() == SupportType.ARBITRATION &&
|
||||||
@ -600,9 +605,9 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||||||
showPayoutTxConfirmation(contract,
|
showPayoutTxConfirmation(contract,
|
||||||
disputeResult,
|
disputeResult,
|
||||||
payoutTx,
|
payoutTx,
|
||||||
() -> doClose(closeTicketButton, payoutTx));
|
() -> doClose(closeTicketButton));
|
||||||
} else {
|
} else {
|
||||||
doClose(closeTicketButton, payoutTx);
|
doClose(closeTicketButton);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -654,7 +659,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doClose(Button closeTicketButton, MoneroTxWallet payoutTx) {
|
private void doClose(Button closeTicketButton) {
|
||||||
DisputeManager<? extends DisputeList<Dispute>> disputeManager = getDisputeManager(dispute);
|
DisputeManager<? extends DisputeList<Dispute>> disputeManager = getDisputeManager(dispute);
|
||||||
if (disputeManager == null) {
|
if (disputeManager == null) {
|
||||||
return;
|
return;
|
||||||
@ -663,7 +668,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
|
|||||||
summaryNotesTextArea.textProperty().unbindBidirectional(disputeResult.summaryNotesProperty());
|
summaryNotesTextArea.textProperty().unbindBidirectional(disputeResult.summaryNotesProperty());
|
||||||
|
|
||||||
disputeResult.setCloseDate(new Date());
|
disputeResult.setCloseDate(new Date());
|
||||||
disputesService.closeDisputeTicket(disputeManager, dispute, disputeResult, payoutTx, () -> {
|
disputesService.closeDisputeTicket(disputeManager, dispute, disputeResult, () -> {
|
||||||
if (peersDisputeOptional.isPresent() && !peersDisputeOptional.get().isClosed() && !DevEnv.isDevMode()) {
|
if (peersDisputeOptional.isPresent() && !peersDisputeOptional.get().isClosed() && !DevEnv.isDevMode()) {
|
||||||
new Popup().attention(Res.get("disputeSummaryWindow.close.closePeer")).show();
|
new Popup().attention(Res.get("disputeSummaryWindow.close.closePeer")).show();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user