Search in sources :

Example 1 with Timer

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.");
    }
}
Also used : Tradable(bisq.core.trade.Tradable) Trade(bisq.core.trade.Trade) DisputeCommunicationMessage(bisq.core.arbitration.messages.DisputeCommunicationMessage) WalletException(bisq.core.btc.exceptions.WalletException) AddressFormatException(org.bitcoinj.core.AddressFormatException) Optional(java.util.Optional) TransactionVerificationException(bisq.core.btc.exceptions.TransactionVerificationException) Transaction(org.bitcoinj.core.Transaction) Timer(bisq.common.Timer) Contract(bisq.core.trade.Contract) DeterministicKey(org.bitcoinj.crypto.DeterministicKey)

Example 2 with Timer

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);
        }
    }
}
Also used : Transaction(org.bitcoinj.core.Transaction) Timer(bisq.common.Timer)

Example 3 with Timer

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);
        }
    }
}
Also used : Timer(bisq.common.Timer)

Example 4 with Timer

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);
            });
        }
    });
}
Also used : Timer(bisq.common.Timer) Transaction(org.bitcoinj.core.Transaction)

Example 5 with Timer

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;
}
Also used : HBox(javafx.scene.layout.HBox) Insets(javafx.geometry.Insets) BusyAnimation(bisq.desktop.components.BusyAnimation) Timer(bisq.common.Timer) Button(javafx.scene.control.Button) ToggleButton(javafx.scene.control.ToggleButton) AutoTooltipButton(bisq.desktop.components.AutoTooltipButton) AutoTooltipToggleButton(bisq.desktop.components.AutoTooltipToggleButton) ImageView(javafx.scene.image.ImageView) AutoTooltipLabel(bisq.desktop.components.AutoTooltipLabel) VBox(javafx.scene.layout.VBox) ProgressBar(javafx.scene.control.ProgressBar) AutoTooltipButton(bisq.desktop.components.AutoTooltipButton)

Aggregations

Timer (bisq.common.Timer)8 Transaction (org.bitcoinj.core.Transaction)4 UserThread (bisq.common.UserThread)2 BisqEnvironment (bisq.core.app.BisqEnvironment)2 AddressEntry (bisq.core.btc.AddressEntry)2 Trade (bisq.core.trade.Trade)2 Optional (java.util.Optional)2 Clock (bisq.common.Clock)1 DevEnv (bisq.common.app.DevEnv)1 Log (bisq.common.app.Log)1 Version (bisq.common.app.Version)1 CryptoException (bisq.common.crypto.CryptoException)1 KeyRing (bisq.common.crypto.KeyRing)1 SealedAndSigned (bisq.common.crypto.SealedAndSigned)1 ExceptionHandler (bisq.common.handlers.ExceptionHandler)1 ResultHandler (bisq.common.handlers.ResultHandler)1 FileUtil (bisq.common.storage.FileUtil)1 Alert (bisq.core.alert.Alert)1 AlertManager (bisq.core.alert.AlertManager)1 PrivateNotificationManager (bisq.core.alert.PrivateNotificationManager)1