use of bisq.common.Timer 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) {
DisputeResult disputeResult = disputeResultMessage.getDisputeResult();
if (!isArbitrator(disputeResult)) {
final String tradeId = disputeResult.getTradeId();
Optional<Dispute> disputeOptional = findDispute(tradeId, disputeResult.getTraderId());
final String uid = disputeResultMessage.getUid();
if (disputeOptional.isPresent()) {
cleanupRetryMap(uid);
Dispute dispute = disputeOptional.get();
DisputeCommunicationMessage disputeCommunicationMessage = disputeResult.getDisputeCommunicationMessage();
if (!dispute.getDisputeCommunicationMessages().contains(disputeCommunicationMessage))
dispute.addDisputeMessage(disputeCommunicationMessage);
else
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) {
try {
log.debug("do payout Transaction ");
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);
log.debug("broadcast committedDisputedPayoutTx");
tradeWalletService.broadcastTx(committedDisputedPayoutTx, new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.debug("BroadcastTx succeeded. 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());
if (openOfferOptional.isPresent())
openOfferManager.closeOpenOffer(openOfferOptional.get().getOffer());
}
}
@Override
public void onFailure(@NotNull Throwable t) {
log.error(t.getMessage());
}
}, 15);
} catch (AddressFormatException | WalletException | TransactionVerificationException e) {
e.printStackTrace();
log.error("Error at traderSignAndFinalizeDisputedPayoutTx " + e.getMessage());
throw new RuntimeException("Error at traderSignAndFinalizeDisputedPayoutTx " + e.toString());
}
} else {
log.warn("DepositTx is null. TradeId = " + tradeId);
}
} 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);
}
} 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());
}
} else {
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);
}
}
} else {
log.error("Arbitrator received disputeResultMessage. That must never happen.");
}
}
use of bisq.common.Timer in project bisq-core by bisq-network.
the class DisputeManager method onDisputedPayoutTxMessage.
// losing trader or in case of 50/50 the seller gets the tx sent from the winner or buyer
private void onDisputedPayoutTxMessage(PeerPublishedDisputePayoutTxMessage peerPublishedDisputePayoutTxMessage) {
final String uid = peerPublishedDisputePayoutTxMessage.getUid();
final String tradeId = peerPublishedDisputePayoutTxMessage.getTradeId();
Optional<Dispute> disputeOptional = findOwnDispute(tradeId);
if (disputeOptional.isPresent()) {
cleanupRetryMap(uid);
Transaction walletTx = tradeWalletService.addTxToWallet(peerPublishedDisputePayoutTxMessage.getTransaction());
disputeOptional.get().setDisputePayoutTxId(walletTx.getHashAsString());
BtcWalletService.printTx("Disputed payoutTx received from peer", walletTx);
} else {
log.debug("We got a peerPublishedPayoutTxMessage but we don't have a matching dispute. TradeId = " + tradeId);
if (!delayMsgMap.containsKey(uid)) {
// We delay 3 sec. to be sure the close msg gets added first
Timer timer = UserThread.runAfter(() -> onDisputedPayoutTxMessage(peerPublishedDisputePayoutTxMessage), 3);
delayMsgMap.put(uid, timer);
} else {
log.warn("We got a peerPublishedPayoutTxMessage after we already repeated to apply the message after a delay. " + "That should never happen. TradeId = " + tradeId);
}
}
}
use of bisq.common.Timer in project bisq-core by bisq-network.
the class DisputeManager method onDisputeDirectMessage.
// a trader can receive a msg from the arbitrator or the arbitrator form a trader. Trader to trader is not allowed.
private void onDisputeDirectMessage(DisputeCommunicationMessage disputeCommunicationMessage) {
Log.traceCall("disputeCommunicationMessage " + disputeCommunicationMessage);
final String tradeId = disputeCommunicationMessage.getTradeId();
Optional<Dispute> disputeOptional = findDispute(tradeId, disputeCommunicationMessage.getTraderId());
final String uid = disputeCommunicationMessage.getUid();
if (disputeOptional.isPresent()) {
cleanupRetryMap(uid);
Dispute dispute = disputeOptional.get();
if (!dispute.getDisputeCommunicationMessages().contains(disputeCommunicationMessage))
dispute.addDisputeMessage(disputeCommunicationMessage);
else
log.warn("We got a disputeCommunicationMessage what we have already stored. TradeId = " + tradeId);
} else {
log.debug("We got a disputeCommunicationMessage but we don't have a matching dispute. TradeId = " + tradeId);
if (!delayMsgMap.containsKey(uid)) {
Timer timer = UserThread.runAfter(() -> onDisputeDirectMessage(disputeCommunicationMessage), 1);
delayMsgMap.put(uid, timer);
} else {
log.warn("We got a disputeCommunicationMessage after we already repeated to apply the message after a delay. That should never happen. TradeId = " + tradeId);
}
}
}
use of bisq.common.Timer in project bisq-core by bisq-network.
the class Broadcaster method broadcastTx.
public static void broadcastTx(Wallet wallet, PeerGroup peerGroup, Transaction tx, FutureCallback<Transaction> callback, int timeoutInSec) {
final Timer timeoutTimer;
if (!broadcastTimerSet.contains(tx.getHashAsString())) {
timeoutTimer = UserThread.runAfter(() -> {
log.warn("Broadcast of tx {} not completed after {} sec. We optimistically assume that the tx broadcast succeeded and " + "call onSuccess on the callback handler.", tx.getHashAsString(), timeoutInSec);
wallet.maybeCommitTx(tx);
callback.onSuccess(tx);
broadcastTimerSet.remove(tx.getHashAsString());
}, timeoutInSec);
broadcastTimerSet.add(tx.getHashAsString());
} else {
timeoutTimer = null;
}
Futures.addCallback(peerGroup.broadcastTransaction(tx).future(), new FutureCallback<Transaction>() {
@Override
public void onSuccess(@Nullable Transaction result) {
// At regtest we get called immediately back but we want to make sure that the handler is not called
// before the caller is finished.
UserThread.execute(() -> {
if (broadcastTimerSet.contains(tx.getHashAsString())) {
// If the timeout has not been called we call the callback.onSuccess
stopAndRemoveTimer(timeoutTimer, tx);
if (result != null)
wallet.maybeCommitTx(result);
callback.onSuccess(tx);
} else {
// Timeout was triggered, nothing to do anymore.
log.info("onSuccess for tx {} was already called from timeout handler. ", tx.getHashAsString());
}
});
}
@Override
public void onFailure(@NotNull Throwable t) {
UserThread.execute(() -> {
stopAndRemoveTimer(timeoutTimer, tx);
callback.onFailure(t);
});
}
});
}
use of bisq.common.Timer in project bisq-desktop by bisq-network.
the class MainView method createSplashScreen.
private VBox createSplashScreen() {
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
vBox.setSpacing(0);
vBox.setId("splash");
ImageView logo = new ImageView();
logo.setId("image-splash-logo");
// createBitcoinInfoBox
btcSplashInfo = new AutoTooltipLabel();
btcSplashInfo.textProperty().bind(model.btcInfo);
walletServiceErrorMsgListener = (ov, oldValue, newValue) -> {
btcSplashInfo.setId("splash-error-state-msg");
btcSplashInfo.getStyleClass().add("error-text");
};
model.walletServiceErrorMsg.addListener(walletServiceErrorMsgListener);
btcSyncIndicator = new ProgressBar();
btcSyncIndicator.setPrefWidth(120);
btcSyncIndicator.progressProperty().bind(model.btcSyncProgress);
ImageView btcSyncIcon = new ImageView();
btcSyncIcon.setVisible(false);
btcSyncIcon.setManaged(false);
btcSyncIconIdListener = (ov, oldValue, newValue) -> {
btcSyncIcon.setId(newValue);
btcSyncIcon.setVisible(true);
btcSyncIcon.setManaged(true);
btcSyncIndicator.setVisible(false);
btcSyncIndicator.setManaged(false);
};
model.btcSplashSyncIconId.addListener(btcSyncIconIdListener);
HBox blockchainSyncBox = new HBox();
blockchainSyncBox.setSpacing(10);
blockchainSyncBox.setAlignment(Pos.CENTER);
blockchainSyncBox.setPadding(new Insets(40, 0, 0, 0));
blockchainSyncBox.setPrefHeight(50);
blockchainSyncBox.getChildren().addAll(btcSplashInfo, btcSyncIndicator, btcSyncIcon);
// create P2PNetworkBox
splashP2PNetworkLabel = new AutoTooltipLabel();
splashP2PNetworkLabel.setWrapText(true);
splashP2PNetworkLabel.setMaxWidth(500);
splashP2PNetworkLabel.setTextAlignment(TextAlignment.CENTER);
splashP2PNetworkLabel.textProperty().bind(model.p2PNetworkInfo);
splashP2PNetworkBusyAnimation = new BusyAnimation();
splashP2PNetworkErrorMsgListener = (ov, oldValue, newValue) -> {
if (newValue != null) {
splashP2PNetworkLabel.setId("splash-error-state-msg");
splashP2PNetworkLabel.getStyleClass().add("error-text");
splashP2PNetworkBusyAnimation.stop();
} else if (model.splashP2PNetworkAnimationVisible.get()) {
splashP2PNetworkBusyAnimation.play();
}
};
model.p2pNetworkWarnMsg.addListener(splashP2PNetworkErrorMsgListener);
Button showTorNetworkSettingsButton = new AutoTooltipButton(Res.get("settings.net.openTorSettingsButton"));
showTorNetworkSettingsButton.setVisible(false);
showTorNetworkSettingsButton.setManaged(false);
showTorNetworkSettingsButton.setOnAction(e -> {
model.torNetworkSettingsWindow.show();
});
ImageView splashP2PNetworkIcon = new ImageView();
splashP2PNetworkIcon.setId("image-connection-tor");
splashP2PNetworkIcon.setVisible(false);
splashP2PNetworkIcon.setManaged(false);
HBox.setMargin(splashP2PNetworkIcon, new Insets(0, 0, 5, 0));
Timer showTorNetworkSettingsTimer = UserThread.runAfter(() -> {
showTorNetworkSettingsButton.setVisible(true);
showTorNetworkSettingsButton.setManaged(true);
}, SHOW_TOR_SETTINGS_DELAY_SEC);
splashP2PNetworkIconIdListener = (ov, oldValue, newValue) -> {
splashP2PNetworkIcon.setId(newValue);
splashP2PNetworkIcon.setVisible(true);
splashP2PNetworkIcon.setManaged(true);
// if we can connect in 10 sec. we know that tor is working
showTorNetworkSettingsTimer.stop();
};
model.p2PNetworkIconId.addListener(splashP2PNetworkIconIdListener);
splashP2PNetworkVisibleListener = (ov, oldValue, newValue) -> splashP2PNetworkBusyAnimation.setIsRunning(newValue);
model.splashP2PNetworkAnimationVisible.addListener(splashP2PNetworkVisibleListener);
HBox splashP2PNetworkBox = new HBox();
splashP2PNetworkBox.setSpacing(10);
splashP2PNetworkBox.setAlignment(Pos.CENTER);
splashP2PNetworkBox.setPrefHeight(50);
splashP2PNetworkBox.getChildren().addAll(splashP2PNetworkLabel, splashP2PNetworkBusyAnimation, splashP2PNetworkIcon, showTorNetworkSettingsButton);
vBox.getChildren().addAll(logo, blockchainSyncBox, splashP2PNetworkBox);
return vBox;
}
Aggregations