Skip to content

Commit f1ff8b5

Browse files
committed
refactor dispute preparation and requesting off main thread
1 parent f6902ae commit f1ff8b5

35 files changed

+409
-239
lines changed

core/src/main/java/haveno/core/api/CoreDisputesService.java

Lines changed: 43 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import com.google.inject.Singleton;
2323
import com.google.inject.name.Named;
2424

25-
import haveno.common.ThreadUtils;
2625
import haveno.common.crypto.KeyRing;
2726
import haveno.common.crypto.PubKeyRing;
2827
import haveno.common.handlers.FaultHandler;
@@ -101,57 +100,51 @@ public Dispute getDispute(String tradeId) {
101100
public void openDispute(String tradeId, ResultHandler resultHandler, FaultHandler faultHandler) {
102101
Trade trade = tradeManager.getOpenTrade(tradeId).orElseThrow(() ->
103102
new IllegalArgumentException(format("trade with id '%s' not found", tradeId)));
104-
105-
// open dispute on trade thread
106-
ThreadUtils.execute(() -> {
107-
Offer offer = trade.getOffer();
108-
if (offer == null) throw new IllegalStateException(format("offer with tradeId '%s' is null", tradeId));
109-
110-
// Dispute agents are registered as mediators and refund agents, but current UI appears to be hardcoded
111-
// to reference the arbitrator. Reference code is in desktop PendingTradesDataModel.java and could be refactored.
112-
var disputeManager = arbitrationManager;
113-
var isSupportTicket = false;
114-
var isMaker = tradeManager.isMyOffer(offer);
115-
var dispute = createDisputeForTrade(trade, offer, keyRing.getPubKeyRing(), isMaker, isSupportTicket);
116-
117-
// Sends the openNewDisputeMessage to arbitrator, who will then create 2 disputes
118-
// one for the opener, the other for the peer, see sendPeerOpenedDisputeMessage.
119-
disputeManager.sendDisputeOpenedMessage(dispute, resultHandler, faultHandler);
120-
tradeManager.requestPersistence();
121-
}, trade.getId());
103+
Offer offer = trade.getOffer();
104+
if (offer == null) throw new IllegalStateException(format("offer with tradeId '%s' is null", tradeId));
105+
106+
// Dispute agents are registered as mediators and refund agents, but current UI appears to be hardcoded
107+
// to reference the arbitrator. Reference code is in desktop PendingTradesDataModel.java and could be refactored.
108+
var disputeManager = arbitrationManager;
109+
var isSupportTicket = false;
110+
var isMaker = tradeManager.isMyOffer(offer);
111+
var dispute = createDisputeForTrade(trade, offer, keyRing.getPubKeyRing(), isMaker, isSupportTicket);
112+
113+
// Sends the openNewDisputeMessage to arbitrator, who will then create 2 disputes
114+
// one for the opener, the other for the peer, see sendPeerOpenedDisputeMessage.
115+
disputeManager.sendDisputeOpenedMessage(dispute, resultHandler, faultHandler);
116+
tradeManager.requestPersistence();
122117
}
123118

124119
public Dispute createDisputeForTrade(Trade trade, Offer offer, PubKeyRing pubKey, boolean isMaker, boolean isSupportTicket) {
125-
synchronized (trade.getLock()) {
126-
byte[] payoutTxSerialized = null;
127-
String payoutTxHashAsString = null;
128-
129-
PubKeyRing arbitratorPubKeyRing = trade.getArbitrator().getPubKeyRing();
130-
checkNotNull(arbitratorPubKeyRing, "arbitratorPubKeyRing must not be null");
131-
Dispute dispute = new Dispute(new Date().getTime(),
132-
trade.getId(),
133-
pubKey.hashCode(), // trader id,
134-
true,
135-
(offer.getDirection() == OfferDirection.BUY) == isMaker,
136-
isMaker,
137-
pubKey,
138-
trade.getDate().getTime(),
139-
trade.getMaxTradePeriodDate().getTime(),
140-
trade.getContract(),
141-
trade.getContractHash(),
142-
payoutTxSerialized,
143-
payoutTxHashAsString,
144-
trade.getContractAsJson(),
145-
trade.getMaker().getContractSignature(),
146-
trade.getTaker().getContractSignature(),
147-
trade.getMaker().getPaymentAccountPayload(),
148-
trade.getTaker().getPaymentAccountPayload(),
149-
arbitratorPubKeyRing,
150-
isSupportTicket,
151-
SupportType.ARBITRATION);
152-
153-
return dispute;
154-
}
120+
byte[] payoutTxSerialized = null;
121+
String payoutTxHashAsString = null;
122+
123+
PubKeyRing arbitratorPubKeyRing = trade.getArbitrator().getPubKeyRing();
124+
checkNotNull(arbitratorPubKeyRing, "arbitratorPubKeyRing must not be null");
125+
Dispute dispute = new Dispute(new Date().getTime(),
126+
trade.getId(),
127+
pubKey.hashCode(), // trader id,
128+
true,
129+
(offer.getDirection() == OfferDirection.BUY) == isMaker,
130+
isMaker,
131+
pubKey,
132+
trade.getDate().getTime(),
133+
trade.getMaxTradePeriodDate().getTime(),
134+
trade.getContract(),
135+
trade.getContractHash(),
136+
payoutTxSerialized,
137+
payoutTxHashAsString,
138+
trade.getContractAsJson(),
139+
trade.getMaker().getContractSignature(),
140+
trade.getTaker().getContractSignature(),
141+
trade.getMaker().getPaymentAccountPayload(),
142+
trade.getTaker().getPaymentAccountPayload(),
143+
arbitratorPubKeyRing,
144+
isSupportTicket,
145+
SupportType.ARBITRATION);
146+
147+
return dispute;
155148
}
156149

157150
// TODO: does not wait for success or error response
@@ -313,6 +306,7 @@ public void sendDisputeChatMessage(String disputeId, String message, ArrayList<A
313306
Dispute dispute;
314307
if (disputeOptional.isPresent()) dispute = disputeOptional.get();
315308
else throw new IllegalStateException(format("dispute with id '%s' not found", disputeId));
309+
if (!arbitrationManager.canSendChatMessages(dispute)) throw new IllegalStateException(format("dispute with id '%s' cannot send chat messages (must be open or stored to mailbox)", disputeId));
316310
ChatMessage chatMessage = new ChatMessage(
317311
arbitrationManager.getSupportType(),
318312
dispute.getTradeId(),

core/src/main/java/haveno/core/support/SupportManager.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ public SupportManager(P2PService p2PService,
122122

123123
public abstract void requestPersistence();
124124

125+
public abstract void persistNow(@Nullable Runnable completeHandler);
126+
125127

126128
///////////////////////////////////////////////////////////////////////////////////////////
127129
// Delegates p2pService
@@ -217,14 +219,10 @@ private void onAckMessage(AckMessage ackMessage) {
217219
synchronized (dispute.getChatMessages()) {
218220
for (ChatMessage chatMessage : dispute.getChatMessages()) {
219221
if (chatMessage.getUid().equals(ackMessage.getSourceUid())) {
220-
if (trade.getDisputeState().isRequested()) {
222+
if (!trade.isArbitrator() && (trade.getDisputeState().isRequested() || trade.getDisputeState().isCloseRequested())) {
221223
log.warn("DisputeOpenedMessage was nacked. We close the dispute now. tradeId={}, nack sender={}", trade.getId(), ackMessage.getSenderNodeAddress());
222224
dispute.setIsClosed();
223225
trade.advanceDisputeState(Trade.DisputeState.DISPUTE_CLOSED);
224-
} else if (trade.getDisputeState().isCloseRequested()) {
225-
log.warn("DisputeCloseMessage was nacked. We close the dispute now. tradeId={}, nack sender={}", trade.getId(), ackMessage.getSenderNodeAddress());
226-
dispute.setIsClosed();
227-
trade.advanceDisputeState(Trade.DisputeState.DISPUTE_CLOSED);
228226
}
229227
}
230228
}
@@ -243,6 +241,9 @@ private void onAckMessage(AckMessage ackMessage) {
243241
msg.setAckError(ackMessage.getErrorMessage());
244242
});
245243
});
244+
245+
tradeManager.persistNow(null);
246+
persistNow(null);
246247
requestPersistence();
247248
}
248249
}
@@ -266,7 +267,7 @@ public ChatMessage sendChatMessage(ChatMessage message) {
266267

267268
mailboxMessageService.sendEncryptedMailboxMessage(peersNodeAddress,
268269
receiverPubKeyRing,
269-
message,
270+
message.copy(),
270271
new SendMailboxMessageListener() {
271272
@Override
272273
public void onArrived() {

core/src/main/java/haveno/core/support/dispute/DisputeListService.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,12 @@ private void onDisputesChangeListener(List<? extends Dispute> addedList,
159159
EasyBind.subscribe(dispute.getBadgeCountProperty(),
160160
isAlerting -> {
161161
// We get the event before the list gets updated, so we execute on next frame
162-
UserThread.execute(() -> {
163-
synchronized (disputeList.getObservableList()) {
164-
int numAlerts = (int) disputeList.getList().stream()
165-
.mapToLong(x -> x.getBadgeCountProperty().getValue())
166-
.sum();
167-
numOpenDisputes.set(numAlerts);
168-
}
169-
});
162+
synchronized (disputeList.getObservableList()) {
163+
int numAlerts = (int) disputeList.getList().stream()
164+
.mapToLong(x -> x.getBadgeCountProperty().getValue())
165+
.sum();
166+
UserThread.execute(() -> numOpenDisputes.set(numAlerts));
167+
}
170168
});
171169
disputedTradeIds.add(dispute.getTradeId());
172170
});
@@ -176,4 +174,8 @@ private void onDisputesChangeListener(List<? extends Dispute> addedList,
176174
public void requestPersistence() {
177175
persistenceManager.requestPersistence();
178176
}
177+
178+
public void persistNow(@Nullable Runnable completeHandler) {
179+
persistenceManager.persistNow(completeHandler);
180+
}
179181
}

0 commit comments

Comments
 (0)