use of bisq.network.p2p.AckMessage in project bisq-core by bisq-network.
the class OpenOfferManager method sendAckMessage.
private void sendAckMessage(OfferAvailabilityRequest message, NodeAddress sender, boolean result, String errorMessage) {
String offerId = message.getOfferId();
String sourceUid = message.getUid();
AckMessage ackMessage = new AckMessage(p2PService.getNetworkNode().getNodeAddress(), AckMessageSourceType.OFFER_MESSAGE, message.getClass().getSimpleName(), sourceUid, offerId, result, errorMessage);
final NodeAddress takersNodeAddress = sender;
PubKeyRing takersPubKeyRing = message.getPubKeyRing();
log.info("Send AckMessage for OfferAvailabilityRequest to peer {} with offerId {} and sourceUid {}", takersNodeAddress, offerId, ackMessage.getSourceUid());
p2PService.sendEncryptedDirectMessage(takersNodeAddress, takersPubKeyRing, ackMessage, new SendDirectMessageListener() {
@Override
public void onArrived() {
log.info("AckMessage for OfferAvailabilityRequest arrived at takersNodeAddress {}. offerId={}, sourceUid={}", takersNodeAddress, offerId, ackMessage.getSourceUid());
}
@Override
public void onFault(String errorMessage) {
log.error("AckMessage for OfferAvailabilityRequest failed. AckMessage={}, takersNodeAddress={}, errorMessage={}", ackMessage, takersNodeAddress, errorMessage);
}
});
}
use of bisq.network.p2p.AckMessage in project bisq-core by bisq-network.
the class OfferAvailabilityProtocol method sendAckMessage.
private void sendAckMessage(OfferAvailabilityResponse message, boolean result, @Nullable String errorMessage) {
String offerId = message.getOfferId();
String sourceUid = message.getUid();
final NodeAddress makersNodeAddress = model.getPeerNodeAddress();
PubKeyRing makersPubKeyRing = model.getOffer().getPubKeyRing();
log.info("Send AckMessage for OfferAvailabilityResponse to peer {} with offerId {} and sourceUid {}", makersNodeAddress, offerId, sourceUid);
AckMessage ackMessage = new AckMessage(model.getP2PService().getNetworkNode().getNodeAddress(), AckMessageSourceType.OFFER_MESSAGE, message.getClass().getSimpleName(), sourceUid, offerId, result, errorMessage);
model.getP2PService().sendEncryptedDirectMessage(makersNodeAddress, makersPubKeyRing, ackMessage, new SendDirectMessageListener() {
@Override
public void onArrived() {
log.info("AckMessage for OfferAvailabilityResponse arrived at makersNodeAddress {}. " + "offerId={}, sourceUid={}", makersNodeAddress, offerId, ackMessage.getSourceUid());
}
@Override
public void onFault(String errorMessage) {
log.error("AckMessage for OfferAvailabilityResponse failed. AckMessage={}, " + "makersNodeAddress={}, errorMessage={}", ackMessage, makersNodeAddress, errorMessage);
}
});
}
use of bisq.network.p2p.AckMessage in project bisq-core by bisq-network.
the class DisputeManager method applyMessages.
private void applyMessages() {
decryptedDirectMessageWithPubKeys.forEach(decryptedMessageWithPubKey -> {
NetworkEnvelope networkEnvelope = decryptedMessageWithPubKey.getNetworkEnvelope();
if (networkEnvelope instanceof DisputeMessage) {
dispatchMessage((DisputeMessage) networkEnvelope);
} else if (networkEnvelope instanceof AckMessage) {
processAckMessage((AckMessage) networkEnvelope, null);
}
});
decryptedDirectMessageWithPubKeys.clear();
decryptedMailboxMessageWithPubKeys.forEach(decryptedMessageWithPubKey -> {
NetworkEnvelope networkEnvelope = decryptedMessageWithPubKey.getNetworkEnvelope();
log.debug("decryptedMessageWithPubKey.message " + networkEnvelope);
if (networkEnvelope instanceof DisputeMessage) {
dispatchMessage((DisputeMessage) networkEnvelope);
p2PService.removeEntryFromMailbox(decryptedMessageWithPubKey);
} else if (networkEnvelope instanceof AckMessage) {
processAckMessage((AckMessage) networkEnvelope, decryptedMessageWithPubKey);
}
});
decryptedMailboxMessageWithPubKeys.clear();
}
use of bisq.network.p2p.AckMessage in project bisq-core by bisq-network.
the class DisputeManager method sendAckMessage.
private void sendAckMessage(DisputeMessage disputeMessage, PubKeyRing peersPubKeyRing, boolean result, @Nullable String errorMessage) {
String tradeId = disputeMessage.getTradeId();
String uid = disputeMessage.getUid();
AckMessage ackMessage = new AckMessage(p2PService.getNetworkNode().getNodeAddress(), AckMessageSourceType.DISPUTE_MESSAGE, disputeMessage.getClass().getSimpleName(), uid, tradeId, result, errorMessage);
final NodeAddress peersNodeAddress = disputeMessage.getSenderNodeAddress();
log.info("Send AckMessage for {} to peer {}. tradeId={}, uid={}", ackMessage.getSourceMsgClassName(), peersNodeAddress, tradeId, uid);
p2PService.sendEncryptedMailboxMessage(peersNodeAddress, peersPubKeyRing, ackMessage, new SendMailboxMessageListener() {
@Override
public void onArrived() {
log.info("AckMessage for {} arrived at peer {}. tradeId={}, uid={}", ackMessage.getSourceMsgClassName(), peersNodeAddress, tradeId, uid);
}
@Override
public void onStoredInMailbox() {
log.info("AckMessage for {} stored in mailbox for peer {}. tradeId={}, uid={}", ackMessage.getSourceMsgClassName(), peersNodeAddress, tradeId, uid);
}
@Override
public void onFault(String errorMessage) {
log.error("AckMessage for {} failed. Peer {}. tradeId={}, uid={}, errorMessage={}", ackMessage.getSourceMsgClassName(), peersNodeAddress, tradeId, uid, errorMessage);
}
});
}
use of bisq.network.p2p.AckMessage in project bisq-core by bisq-network.
the class DisputeManager method onDisputeResultMessage.
// We get that message at both peers. The dispute object is in context of the trader
private void onDisputeResultMessage(DisputeResultMessage disputeResultMessage) {
String errorMessage = null;
boolean success = false;
PubKeyRing arbitratorsPubKeyRing = null;
DisputeResult disputeResult = disputeResultMessage.getDisputeResult();
if (isArbitrator(disputeResult)) {
log.error("Arbitrator received disputeResultMessage. That must never happen.");
return;
}
final String tradeId = disputeResult.getTradeId();
Optional<Dispute> disputeOptional = findDispute(tradeId, disputeResult.getTraderId());
final String uid = disputeResultMessage.getUid();
if (!disputeOptional.isPresent()) {
log.debug("We got a dispute result msg but we don't have a matching dispute. " + "That might happen when we get the disputeResultMessage before the dispute was created. " + "We try again after 2 sec. to apply the disputeResultMessage. TradeId = " + tradeId);
if (!delayMsgMap.containsKey(uid)) {
// We delay2 sec. to be sure the comm. msg gets added first
Timer timer = UserThread.runAfter(() -> onDisputeResultMessage(disputeResultMessage), 2);
delayMsgMap.put(uid, timer);
} else {
log.warn("We got a dispute result msg after we already repeated to apply the message after a delay. " + "That should never happen. TradeId = " + tradeId);
}
return;
}
try {
cleanupRetryMap(uid);
Dispute dispute = disputeOptional.get();
arbitratorsPubKeyRing = dispute.getArbitratorPubKeyRing();
DisputeCommunicationMessage disputeCommunicationMessage = disputeResult.getDisputeCommunicationMessage();
if (!dispute.getDisputeCommunicationMessages().contains(disputeCommunicationMessage))
dispute.addDisputeCommunicationMessage(disputeCommunicationMessage);
else if (disputeCommunicationMessage != null)
log.warn("We got a dispute mail msg what we have already stored. TradeId = " + disputeCommunicationMessage.getTradeId());
dispute.setIsClosed(true);
if (dispute.disputeResultProperty().get() != null)
log.warn("We got already a dispute result. That should only happen if a dispute needs to be closed " + "again because the first close did not succeed. TradeId = " + tradeId);
dispute.setDisputeResult(disputeResult);
// We need to avoid publishing the tx from both traders as it would create problems with zero confirmation withdrawals
// There would be different transactions if both sign and publish (signers: once buyer+arb, once seller+arb)
// The tx publisher is the winner or in case both get 50% the buyer, as the buyer has more inventive to publish the tx as he receives
// more BTC as he has deposited
final Contract contract = dispute.getContract();
boolean isBuyer = keyRing.getPubKeyRing().equals(contract.getBuyerPubKeyRing());
DisputeResult.Winner publisher = disputeResult.getWinner();
// Default isLoserPublisher is set to false
if (disputeResult.isLoserPublisher()) {
// we invert the logic
if (publisher == DisputeResult.Winner.BUYER)
publisher = DisputeResult.Winner.SELLER;
else if (publisher == DisputeResult.Winner.SELLER)
publisher = DisputeResult.Winner.BUYER;
}
if ((isBuyer && publisher == DisputeResult.Winner.BUYER) || (!isBuyer && publisher == DisputeResult.Winner.SELLER)) {
final Optional<Trade> tradeOptional = tradeManager.getTradeById(tradeId);
Transaction payoutTx = null;
if (tradeOptional.isPresent()) {
payoutTx = tradeOptional.get().getPayoutTx();
} else {
final Optional<Tradable> tradableOptional = closedTradableManager.getTradableById(tradeId);
if (tradableOptional.isPresent() && tradableOptional.get() instanceof Trade) {
payoutTx = ((Trade) tradableOptional.get()).getPayoutTx();
}
}
if (payoutTx == null) {
if (dispute.getDepositTxSerialized() != null) {
byte[] multiSigPubKey = isBuyer ? contract.getBuyerMultiSigPubKey() : contract.getSellerMultiSigPubKey();
DeterministicKey multiSigKeyPair = walletService.getMultiSigKeyPair(dispute.getTradeId(), multiSigPubKey);
Transaction signedDisputedPayoutTx = tradeWalletService.traderSignAndFinalizeDisputedPayoutTx(dispute.getDepositTxSerialized(), disputeResult.getArbitratorSignature(), disputeResult.getBuyerPayoutAmount(), disputeResult.getSellerPayoutAmount(), contract.getBuyerPayoutAddressString(), contract.getSellerPayoutAddressString(), multiSigKeyPair, contract.getBuyerMultiSigPubKey(), contract.getSellerMultiSigPubKey(), disputeResult.getArbitratorPubKey());
Transaction committedDisputedPayoutTx = tradeWalletService.addTxToWallet(signedDisputedPayoutTx);
tradeWalletService.broadcastTx(committedDisputedPayoutTx, new TxBroadcaster.Callback() {
@Override
public void onSuccess(Transaction transaction) {
// after successful publish we send peer the tx
dispute.setDisputePayoutTxId(transaction.getHashAsString());
sendPeerPublishedPayoutTxMessage(transaction, dispute, contract);
// set state after payout as we call swapTradeEntryToAvailableEntry
if (tradeManager.getTradeById(dispute.getTradeId()).isPresent())
tradeManager.closeDisputedTrade(dispute.getTradeId());
else {
Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(dispute.getTradeId());
openOfferOptional.ifPresent(openOffer -> openOfferManager.closeOpenOffer(openOffer.getOffer()));
}
}
@Override
public void onFailure(TxBroadcastException exception) {
log.error(exception.getMessage());
}
}, 15);
success = true;
} else {
errorMessage = "DepositTx is null. TradeId = " + tradeId;
log.warn(errorMessage);
success = false;
}
} else {
log.warn("We got already a payout tx. That might be the case if the other peer did not get the " + "payout tx and opened a dispute. TradeId = " + tradeId);
dispute.setDisputePayoutTxId(payoutTx.getHashAsString());
sendPeerPublishedPayoutTxMessage(payoutTx, dispute, contract);
success = true;
}
} else {
log.trace("We don't publish the tx as we are not the winning party.");
// Clean up tangling trades
if (dispute.disputeResultProperty().get() != null && dispute.isClosed() && tradeManager.getTradeById(dispute.getTradeId()).isPresent()) {
tradeManager.closeDisputedTrade(dispute.getTradeId());
}
success = true;
}
} catch (AddressFormatException | WalletException | TransactionVerificationException e) {
e.printStackTrace();
errorMessage = "Error at traderSignAndFinalizeDisputedPayoutTx " + e.toString();
log.error(errorMessage);
success = false;
throw new RuntimeException(errorMessage);
} finally {
if (arbitratorsPubKeyRing != null) {
// We use the disputeCommunicationMessage as we only persist those not the disputeResultMessage.
// If we would use the disputeResultMessage we could not lookup for the msg when we receive the AckMessage.
DisputeCommunicationMessage disputeCommunicationMessage = disputeResultMessage.getDisputeResult().getDisputeCommunicationMessage();
sendAckMessage(disputeCommunicationMessage, arbitratorsPubKeyRing, success, errorMessage);
}
}
}
Aggregations