diff --git a/core/src/main/java/io/bitsquare/arbitration/ArbitratorManager.java b/core/src/main/java/io/bitsquare/arbitration/ArbitratorManager.java index c12f28f1aa..012be56c88 100644 --- a/core/src/main/java/io/bitsquare/arbitration/ArbitratorManager.java +++ b/core/src/main/java/io/bitsquare/arbitration/ArbitratorManager.java @@ -145,8 +145,12 @@ public class ArbitratorManager { ArbitratorManager.this.onBootstrapComplete(); } }; - p2PService.addP2PServiceListener(bootstrapListener); + if (p2PService.isBootstrapped()) + onBootstrapComplete(); + else + p2PService.addP2PServiceListener(bootstrapListener); + } else { republishArbitrator(); } diff --git a/core/src/main/java/io/bitsquare/arbitration/DisputeManager.java b/core/src/main/java/io/bitsquare/arbitration/DisputeManager.java index 66843ddbba..8de595d933 100644 --- a/core/src/main/java/io/bitsquare/arbitration/DisputeManager.java +++ b/core/src/main/java/io/bitsquare/arbitration/DisputeManager.java @@ -125,7 +125,10 @@ public class DisputeManager { applyMessages(); } }; - p2PService.addP2PServiceListener(bootstrapListener); + if (p2PService.isBootstrapped()) + applyMessages(); + else + p2PService.addP2PServiceListener(bootstrapListener); } private void applyMessages() { @@ -146,7 +149,8 @@ public class DisputeManager { }); decryptedMailboxMessageWithPubKeys.clear(); - p2PService.removeP2PServiceListener(bootstrapListener); + if (bootstrapListener != null) + p2PService.removeP2PServiceListener(bootstrapListener); } diff --git a/core/src/main/java/io/bitsquare/trade/TradeManager.java b/core/src/main/java/io/bitsquare/trade/TradeManager.java index 521b1b4d9d..5e74fb17f7 100644 --- a/core/src/main/java/io/bitsquare/trade/TradeManager.java +++ b/core/src/main/java/io/bitsquare/trade/TradeManager.java @@ -151,13 +151,15 @@ public class TradeManager { bootstrapListener = new BootstrapListener() { @Override public void onBootstrapComplete() { - Log.traceCall("onNetworkReady"); // Get called after onMailboxMessageAdded from initial data request // The mailbox message will be removed inside the tasks after they are processed successfully initPendingTrades(); } }; - p2PService.addP2PServiceListener(bootstrapListener); + if (p2PService.isBootstrapped()) + initPendingTrades(); + else + p2PService.addP2PServiceListener(bootstrapListener); } @@ -167,7 +169,8 @@ public class TradeManager { private void initPendingTrades() { Log.traceCall(); - p2PService.removeP2PServiceListener(bootstrapListener); + if (bootstrapListener != null) + p2PService.removeP2PServiceListener(bootstrapListener); //List failedTrades = new ArrayList<>(); for (Trade trade : trades) { diff --git a/core/src/main/java/io/bitsquare/trade/offer/OpenOfferManager.java b/core/src/main/java/io/bitsquare/trade/offer/OpenOfferManager.java index 7a3847d75b..7744936218 100644 --- a/core/src/main/java/io/bitsquare/trade/offer/OpenOfferManager.java +++ b/core/src/main/java/io/bitsquare/trade/offer/OpenOfferManager.java @@ -53,6 +53,7 @@ import javax.annotation.Nullable; import javax.inject.Named; import java.io.File; import java.util.ArrayList; +import java.util.List; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -121,6 +122,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe }; p2PService.addP2PServiceListener(bootstrapListener); p2PService.addDecryptedDirectMessageListener(this); + + if (p2PService.isBootstrapped()) + onBootstrapComplete(); + else + p2PService.addP2PServiceListener(bootstrapListener); } @SuppressWarnings("WeakerAccess") @@ -151,6 +157,15 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe UserThread.runAfter(completeHandler::run, openOffers.size() * 100 + 200, TimeUnit.MILLISECONDS); } + public void removeAllOpenOffers(@Nullable Runnable completeHandler) { + List openOffersList = new ArrayList<>(openOffers); + openOffersList.forEach(openOffer -> removeOpenOffer(openOffer, () -> { + }, errorMessage -> { + })); + if (completeHandler != null) + UserThread.runAfter(completeHandler::run, openOffers.size() * 100 + 200, TimeUnit.MILLISECONDS); + } + /////////////////////////////////////////////////////////////////////////////////////////// // DecryptedDirectMessageListener implementation /////////////////////////////////////////////////////////////////////////////////////////// @@ -172,7 +187,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe /////////////////////////////////////////////////////////////////////////////////////////// public void onBootstrapComplete() { - p2PService.removeP2PServiceListener(bootstrapListener); + if (bootstrapListener != null) + p2PService.removeP2PServiceListener(bootstrapListener); stopped = false; diff --git a/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java index 4e85b552fa..9a3c36c812 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java @@ -409,13 +409,10 @@ public class MainViewModel implements ViewModel { } private void onAllServicesInitialized() { + // We need to request the password in case we have an encrypted wallet as we need to set the aesKey to our trading wallet. // In case we have any offers open or a pending trade we need to unlock our trading wallet so a trade can be executed automatically - // Otherwise we delay the password request to create offer, or take offer. // When the password is set it will be stored to the tradeWalletService as well, so its only needed after a restart. - if (walletService.getWallet().isEncrypted() && - (openOfferManager.getOpenOffers().size() > 0 - || tradeManager.getTrades().size() > 0 - || disputeManager.getDisputesAsObservableList().size() > 0)) { + if (walletService.getWallet().isEncrypted()) { walletPasswordWindow .onAesKey(aesKey -> { tradeWalletService.setAesKey(aesKey); diff --git a/gui/src/main/java/io/bitsquare/gui/main/account/content/password/PasswordView.java b/gui/src/main/java/io/bitsquare/gui/main/account/content/password/PasswordView.java index 4fc9cc157c..79f2ec1302 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/account/content/password/PasswordView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/account/content/password/PasswordView.java @@ -145,9 +145,7 @@ public class PasswordView extends ActivatableView { addMultilineLabel(root, gridRow, "With password protection you need to enter your password when" + " withdrawing bitcoin out of your wallet or " + - "if you want to view or restore a wallet from seed words.\n" + - "For the transactions used in the trade process we don't support password protection as that would make automatic offer " + - "execution impossible, but you need to provide the password at application startup if you have open offer, trades or disputes.", + "if you want to view or restore a wallet from seed words as well as at application startup.", Layout.FIRST_ROW_AND_GROUP_DISTANCE); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/disputes/trader/TraderDisputeView.java b/gui/src/main/java/io/bitsquare/gui/main/disputes/trader/TraderDisputeView.java index 6c9b5ac9c1..d7a73f61e2 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/disputes/trader/TraderDisputeView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/disputes/trader/TraderDisputeView.java @@ -37,7 +37,6 @@ import io.bitsquare.gui.main.overlays.windows.DisputeSummaryWindow; import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow; import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.GUIUtil; -import io.bitsquare.p2p.BootstrapListener; import io.bitsquare.p2p.P2PService; import io.bitsquare.p2p.network.Connection; import io.bitsquare.trade.Trade; @@ -110,7 +109,6 @@ public class TraderDisputeView extends ActivatableView { private TableGroupHeadline tableGroupHeadline; private ObservableList disputeCommunicationMessages; private Button sendButton; - private boolean isBootstrapped; private Subscription inputTextAreaTextSubscription; @@ -175,17 +173,6 @@ public class TraderDisputeView extends ActivatableView { }; disputeDirectMessageListListener = c -> scrollToBottom(); - - if (!p2PService.isBootstrapped()) { - p2PService.addP2PServiceListener(new BootstrapListener() { - @Override - public void onBootstrapComplete() { - isBootstrapped = true; - } - }); - } else { - isBootstrapped = true; - } } @Override @@ -425,7 +412,7 @@ public class TraderDisputeView extends ActivatableView { sendButton = new Button("Send"); sendButton.setDefaultButton(true); sendButton.setOnAction(e -> { - if (isBootstrapped) { + if (p2PService.isBootstrapped()) { String text = inputTextArea.getText(); if (!text.isEmpty()) onSendMessage(text, selectedDispute); diff --git a/gui/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalView.java b/gui/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalView.java index 77d9e99026..8f08b87c93 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/funds/withdrawal/WithdrawalView.java @@ -25,6 +25,7 @@ import io.bitsquare.btc.AddressEntryException; import io.bitsquare.btc.Restrictions; import io.bitsquare.btc.WalletService; import io.bitsquare.btc.listeners.BalanceListener; +import io.bitsquare.common.UserThread; import io.bitsquare.common.util.Utilities; import io.bitsquare.gui.common.view.ActivatableView; import io.bitsquare.gui.common.view.FxmlView; @@ -58,6 +59,7 @@ import org.spongycastle.crypto.params.KeyParameter; import javax.inject.Inject; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @FxmlView @@ -281,7 +283,9 @@ public class WithdrawalView extends ActivatableView { private void doWithdraw(Coin amount, FutureCallback callback) { if (walletService.getWallet().isEncrypted()) { - walletPasswordWindow.onAesKey(aesKey -> sendFunds(amount, aesKey, callback)).show(); + UserThread.runAfter(() -> walletPasswordWindow.onAesKey(aesKey -> + sendFunds(amount, aesKey, callback)) + .show(), 300, TimeUnit.MILLISECONDS); } else { sendFunds(amount, null, callback); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferDataModel.java index 678192214a..c36b09dfd6 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferDataModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferDataModel.java @@ -30,7 +30,6 @@ import io.bitsquare.common.crypto.KeyRing; import io.bitsquare.gui.Navigation; import io.bitsquare.gui.common.model.ActivatableDataModel; import io.bitsquare.gui.main.overlays.notifications.Notification; -import io.bitsquare.gui.main.overlays.windows.WalletPasswordWindow; import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.locale.TradeCurrency; import io.bitsquare.p2p.P2PService; @@ -63,14 +62,13 @@ import static com.google.common.base.Preconditions.checkNotNull; class CreateOfferDataModel extends ActivatableDataModel { private final OpenOfferManager openOfferManager; final WalletService walletService; - private final TradeWalletService tradeWalletService; + final TradeWalletService tradeWalletService; private final Preferences preferences; private final User user; private final KeyRing keyRing; private final P2PService p2PService; private final PriceFeed priceFeed; private Navigation navigation; - private final WalletPasswordWindow walletPasswordWindow; private final BlockchainService blockchainService; private final BSFormatter formatter; private final String offerId; @@ -117,8 +115,7 @@ class CreateOfferDataModel extends ActivatableDataModel { @Inject CreateOfferDataModel(OpenOfferManager openOfferManager, WalletService walletService, TradeWalletService tradeWalletService, Preferences preferences, User user, KeyRing keyRing, P2PService p2PService, PriceFeed priceFeed, - Navigation navigation, - WalletPasswordWindow walletPasswordWindow, BlockchainService blockchainService, BSFormatter formatter) { + Navigation navigation, BlockchainService blockchainService, BSFormatter formatter) { this.openOfferManager = openOfferManager; this.walletService = walletService; this.tradeWalletService = tradeWalletService; @@ -128,7 +125,6 @@ class CreateOfferDataModel extends ActivatableDataModel { this.p2PService = p2PService; this.priceFeed = priceFeed; this.navigation = navigation; - this.walletPasswordWindow = walletPasswordWindow; this.blockchainService = blockchainService; this.formatter = formatter; @@ -286,17 +282,6 @@ class CreateOfferDataModel extends ActivatableDataModel { } void onPlaceOffer(Offer offer, TransactionResultHandler resultHandler) { - if (walletService.getWallet().isEncrypted() && tradeWalletService.getAesKey() == null) { - walletPasswordWindow.onAesKey(aesKey -> { - tradeWalletService.setAesKey(aesKey); - doPlaceOffer(offer, resultHandler); - }).show(); - } else { - doPlaceOffer(offer, resultHandler); - } - } - - private void doPlaceOffer(Offer offer, TransactionResultHandler resultHandler) { openOfferManager.placeOffer(offer, totalToPayAsCoin.get().subtract(offerFeeAsCoin), useSavingsWallet, resultHandler); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferDataModel.java index 9136e7471e..d008ca89b3 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferDataModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/takeoffer/TakeOfferDataModel.java @@ -29,7 +29,6 @@ import io.bitsquare.btc.listeners.BalanceListener; import io.bitsquare.btc.pricefeed.PriceFeed; import io.bitsquare.gui.common.model.ActivatableDataModel; import io.bitsquare.gui.main.overlays.notifications.Notification; -import io.bitsquare.gui.main.overlays.windows.WalletPasswordWindow; import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.locale.TradeCurrency; @@ -61,10 +60,9 @@ import static com.google.common.base.Preconditions.checkNotNull; */ class TakeOfferDataModel extends ActivatableDataModel { private final TradeManager tradeManager; - private final TradeWalletService tradeWalletService; - private final WalletService walletService; + final TradeWalletService tradeWalletService; + final WalletService walletService; private final User user; - private final WalletPasswordWindow walletPasswordWindow; private final Preferences preferences; private final PriceFeed priceFeed; private final BlockchainService blockchainService; @@ -103,14 +101,13 @@ class TakeOfferDataModel extends ActivatableDataModel { @Inject TakeOfferDataModel(TradeManager tradeManager, TradeWalletService tradeWalletService, - WalletService walletService, User user, WalletPasswordWindow walletPasswordWindow, + WalletService walletService, User user, Preferences preferences, PriceFeed priceFeed, BlockchainService blockchainService, BSFormatter formatter) { this.tradeManager = tradeManager; this.tradeWalletService = tradeWalletService; this.walletService = walletService; this.user = user; - this.walletPasswordWindow = walletPasswordWindow; this.preferences = preferences; this.priceFeed = priceFeed; this.blockchainService = blockchainService; @@ -227,17 +224,6 @@ class TakeOfferDataModel extends ActivatableDataModel { // errorMessageHandler is used only in the check availability phase. As soon we have a trade we write the error msg in the trade object as we want to // have it persisted as well. void onTakeOffer(TradeResultHandler tradeResultHandler) { - if (walletService.getWallet().isEncrypted() && tradeWalletService.getAesKey() == null) { - walletPasswordWindow.onAesKey(aesKey -> { - tradeWalletService.setAesKey(aesKey); - doTakeOffer(tradeResultHandler); - }).show(); - } else { - doTakeOffer(tradeResultHandler); - } - } - - private void doTakeOffer(TradeResultHandler tradeResultHandler) { tradeManager.onTakeOffer(amountAsCoin.get(), totalToPayAsCoin.get().subtract(takerFeeAsCoin), offer, diff --git a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/EmptyWalletWindow.java b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/EmptyWalletWindow.java index f056a7f22c..e9ed675da6 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/EmptyWalletWindow.java +++ b/gui/src/main/java/io/bitsquare/gui/main/overlays/windows/EmptyWalletWindow.java @@ -62,7 +62,8 @@ public class EmptyWalletWindow extends Overlay { /////////////////////////////////////////////////////////////////////////////////////////// @Inject - public EmptyWalletWindow(WalletService walletService, WalletPasswordWindow walletPasswordWindow, OpenOfferManager openOfferManager, BSFormatter formatter) { + public EmptyWalletWindow(WalletService walletService, WalletPasswordWindow walletPasswordWindow, + OpenOfferManager openOfferManager, BSFormatter formatter) { this.walletService = walletService; this.walletPasswordWindow = walletPasswordWindow; this.openOfferManager = openOfferManager; @@ -140,8 +141,23 @@ public class EmptyWalletWindow extends Overlay { } private void doEmptyWallet(KeyParameter aesKey) { + if (!openOfferManager.getOpenOffers().isEmpty()) { + UserThread.runAfter(() -> + new Popup().warning("You have open offers which will be removed if you empty the wallet.\n" + + "Are you sure that you want to empty your wallet?") + .actionButtonText("Yes, I am sure") + .onAction(() -> { + doEmptyWallet2(aesKey); + }) + .show(), 300, TimeUnit.MILLISECONDS); + } else { + doEmptyWallet2(aesKey); + } + } + + private void doEmptyWallet2(KeyParameter aesKey) { emptyWalletButton.setDisable(true); - openOfferManager.closeAllOpenOffers(() -> { + openOfferManager.removeAllOpenOffers(() -> { try { walletService.emptyWallet(addressInputTextField.getText(), aesKey, diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java index eac0180c55..56501330e3 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/buyer/BuyerStep5View.java @@ -23,6 +23,7 @@ import io.bitsquare.btc.AddressEntry; import io.bitsquare.btc.AddressEntryException; import io.bitsquare.btc.Restrictions; import io.bitsquare.btc.WalletService; +import io.bitsquare.common.UserThread; import io.bitsquare.common.handlers.FaultHandler; import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.common.util.Tuple2; @@ -47,6 +48,8 @@ import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.Coin; import org.spongycastle.crypto.params.KeyParameter; +import java.util.concurrent.TimeUnit; + import static io.bitsquare.gui.util.FormBuilder.*; public class BuyerStep5View extends TradeStepView { @@ -223,8 +226,6 @@ public class BuyerStep5View extends TradeStepView { } private void doWithdrawal(Coin receiverAmount) { - useSavingsWalletButton.setDisable(true); - withdrawToExternalWalletButton.setDisable(true); String toAddress = withdrawAddressTextField.getText(); ResultHandler resultHandler = this::handleTradeCompleted; FaultHandler faultHandler = (errorMessage, throwable) -> { @@ -236,17 +237,16 @@ public class BuyerStep5View extends TradeStepView { new Popup().error(errorMessage).show(); }; if (model.dataModel.walletService.getWallet().isEncrypted()) { - model.dataModel.walletPasswordWindow.onAesKey(aesKey -> doWithdrawRequest(toAddress, receiverAmount, aesKey, resultHandler, faultHandler)) - .onClose(() -> { - useSavingsWalletButton.setDisable(false); - withdrawToExternalWalletButton.setDisable(false); - }) - .show(); + UserThread.runAfter(() -> model.dataModel.walletPasswordWindow.onAesKey(aesKey -> + doWithdrawRequest(toAddress, receiverAmount, aesKey, resultHandler, faultHandler)) + .show(), 300, TimeUnit.MILLISECONDS); } else doWithdrawRequest(toAddress, receiverAmount, null, resultHandler, faultHandler); } private void doWithdrawRequest(String toAddress, Coin receiverAmount, KeyParameter aesKey, ResultHandler resultHandler, FaultHandler faultHandler) { + useSavingsWalletButton.setDisable(true); + withdrawToExternalWalletButton.setDisable(true); model.dataModel.onWithdrawRequest(toAddress, receiverAmount, aesKey,