forked from bisq-network/bisq
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request bisq-network#4746 from chimp1984/cleanup-mailbox-m…
…essages-at-closed-trades Clean up mailbox messages for closed trades
- Loading branch information
Showing
4 changed files
with
157 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
129 changes: 129 additions & 0 deletions
129
core/src/main/java/bisq/core/trade/closed/CleanupMailboxMessages.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/* | ||
* This file is part of Bisq. | ||
* | ||
* Bisq 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. | ||
* | ||
* Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
package bisq.core.trade.closed; | ||
|
||
import bisq.core.trade.Trade; | ||
import bisq.core.trade.messages.TradeMessage; | ||
|
||
import bisq.network.p2p.AckMessage; | ||
import bisq.network.p2p.AckMessageSourceType; | ||
import bisq.network.p2p.BootstrapListener; | ||
import bisq.network.p2p.DecryptedMessageWithPubKey; | ||
import bisq.network.p2p.P2PService; | ||
|
||
import bisq.common.crypto.PubKeyRing; | ||
import bisq.common.proto.network.NetworkEnvelope; | ||
|
||
import javax.inject.Inject; | ||
|
||
import java.util.List; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
|
||
/** | ||
* Util for removing pending mailbox messages in case the trade has been closed by the seller after confirming receipt | ||
* and a AckMessage as mailbox message will be sent by the buyer once they go online. In that case the seller's trade | ||
* is closed already and the TradeProtocol is not executing the message processing, thus the mailbox message would not | ||
* be removed. To ensure that in such cases (as well other potential cases in failure scenarios) the mailbox message | ||
* gets removed from the network we use that util. | ||
* | ||
* This class must not be injected as a singleton! | ||
*/ | ||
@Slf4j | ||
public class CleanupMailboxMessages { | ||
private final P2PService p2PService; | ||
|
||
@Inject | ||
public CleanupMailboxMessages(P2PService p2PService) { | ||
this.p2PService = p2PService; | ||
} | ||
|
||
public void handleTrades(List<Trade> trades) { | ||
// We wrap in a try catch as in failed trades we cannot be sure if expected data is set, so we could get | ||
// a NullPointer and do not want that this escalate to the user. | ||
try { | ||
if (p2PService.isBootstrapped()) { | ||
cleanupMailboxMessages(trades); | ||
} else { | ||
p2PService.addP2PServiceListener(new BootstrapListener() { | ||
@Override | ||
public void onUpdatedDataReceived() { | ||
cleanupMailboxMessages(trades); | ||
} | ||
}); | ||
} | ||
} catch (Throwable t) { | ||
log.error("Cleanup mailbox messages failed. {}", t.toString()); | ||
} | ||
} | ||
|
||
private void cleanupMailboxMessages(List<Trade> trades) { | ||
p2PService.getMailboxItemsByUid().values() | ||
.stream().map(P2PService.MailboxItem::getDecryptedMessageWithPubKey) | ||
.forEach(message -> handleDecryptedMessageWithPubKey(message, trades)); | ||
} | ||
|
||
private void handleDecryptedMessageWithPubKey(DecryptedMessageWithPubKey decryptedMessageWithPubKey, | ||
List<Trade> trades) { | ||
trades.forEach(trade -> handleDecryptedMessageWithPubKey(decryptedMessageWithPubKey, trade)); | ||
} | ||
|
||
private void handleDecryptedMessageWithPubKey(DecryptedMessageWithPubKey decryptedMessageWithPubKey, | ||
Trade trade) { | ||
NetworkEnvelope networkEnvelope = decryptedMessageWithPubKey.getNetworkEnvelope(); | ||
if (!isPubKeyValid(decryptedMessageWithPubKey, trade)) { | ||
return; | ||
} | ||
|
||
if (networkEnvelope instanceof TradeMessage && | ||
isMyMessage((TradeMessage) networkEnvelope, trade)) { | ||
removeEntryFromMailbox(decryptedMessageWithPubKey, trade); | ||
} else if (networkEnvelope instanceof AckMessage && | ||
isMyMessage((AckMessage) networkEnvelope, trade)) { | ||
removeEntryFromMailbox(decryptedMessageWithPubKey, trade); | ||
} | ||
} | ||
|
||
private void removeEntryFromMailbox(DecryptedMessageWithPubKey decryptedMessageWithPubKey, Trade trade) { | ||
log.info("We found a pending mailbox message ({}) for trade {}. As the trade is closed we remove the mailbox message.", | ||
decryptedMessageWithPubKey.getNetworkEnvelope().getClass().getSimpleName(), trade.getId()); | ||
p2PService.removeEntryFromMailbox(decryptedMessageWithPubKey); | ||
} | ||
|
||
private boolean isMyMessage(TradeMessage message, Trade trade) { | ||
return message.getTradeId().equals(trade.getId()); | ||
} | ||
|
||
private boolean isMyMessage(AckMessage ackMessage, Trade trade) { | ||
return ackMessage.getSourceType() == AckMessageSourceType.TRADE_MESSAGE && | ||
ackMessage.getSourceId().equals(trade.getId()); | ||
} | ||
|
||
private boolean isPubKeyValid(DecryptedMessageWithPubKey message, Trade trade) { | ||
// We can only validate the peers pubKey if we have it already. If we are the taker we get it from the offer | ||
// Otherwise it depends on the state of the trade protocol if we have received the peers pubKeyRing already. | ||
PubKeyRing peersPubKeyRing = trade.getProcessModel().getTradingPeer().getPubKeyRing(); | ||
boolean isValid = true; | ||
if (peersPubKeyRing != null && | ||
!message.getSignaturePubKey().equals(peersPubKeyRing.getSignaturePubKey())) { | ||
isValid = false; | ||
log.error("SignaturePubKey in message does not match the SignaturePubKey we have set for our trading peer."); | ||
} | ||
return isValid; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters