Require password at startup, heck for open offers at emptying wallet, add check for isBootstrapped,

This commit is contained in:
Manfred Karrer 2016-04-07 02:54:52 +02:00
parent 5af70848a7
commit 0ebf3f6b36
12 changed files with 74 additions and 74 deletions

View file

@ -145,7 +145,11 @@ public class ArbitratorManager {
ArbitratorManager.this.onBootstrapComplete(); ArbitratorManager.this.onBootstrapComplete();
} }
}; };
p2PService.addP2PServiceListener(bootstrapListener);
if (p2PService.isBootstrapped())
onBootstrapComplete();
else
p2PService.addP2PServiceListener(bootstrapListener);
} else { } else {
republishArbitrator(); republishArbitrator();

View file

@ -125,7 +125,10 @@ public class DisputeManager {
applyMessages(); applyMessages();
} }
}; };
p2PService.addP2PServiceListener(bootstrapListener); if (p2PService.isBootstrapped())
applyMessages();
else
p2PService.addP2PServiceListener(bootstrapListener);
} }
private void applyMessages() { private void applyMessages() {
@ -146,7 +149,8 @@ public class DisputeManager {
}); });
decryptedMailboxMessageWithPubKeys.clear(); decryptedMailboxMessageWithPubKeys.clear();
p2PService.removeP2PServiceListener(bootstrapListener); if (bootstrapListener != null)
p2PService.removeP2PServiceListener(bootstrapListener);
} }

View file

@ -151,13 +151,15 @@ public class TradeManager {
bootstrapListener = new BootstrapListener() { bootstrapListener = new BootstrapListener() {
@Override @Override
public void onBootstrapComplete() { public void onBootstrapComplete() {
Log.traceCall("onNetworkReady");
// Get called after onMailboxMessageAdded from initial data request // Get called after onMailboxMessageAdded from initial data request
// The mailbox message will be removed inside the tasks after they are processed successfully // The mailbox message will be removed inside the tasks after they are processed successfully
initPendingTrades(); initPendingTrades();
} }
}; };
p2PService.addP2PServiceListener(bootstrapListener); if (p2PService.isBootstrapped())
initPendingTrades();
else
p2PService.addP2PServiceListener(bootstrapListener);
} }
@ -167,7 +169,8 @@ public class TradeManager {
private void initPendingTrades() { private void initPendingTrades() {
Log.traceCall(); Log.traceCall();
p2PService.removeP2PServiceListener(bootstrapListener); if (bootstrapListener != null)
p2PService.removeP2PServiceListener(bootstrapListener);
//List<Trade> failedTrades = new ArrayList<>(); //List<Trade> failedTrades = new ArrayList<>();
for (Trade trade : trades) { for (Trade trade : trades) {

View file

@ -53,6 +53,7 @@ import javax.annotation.Nullable;
import javax.inject.Named; import javax.inject.Named;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -121,6 +122,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
}; };
p2PService.addP2PServiceListener(bootstrapListener); p2PService.addP2PServiceListener(bootstrapListener);
p2PService.addDecryptedDirectMessageListener(this); p2PService.addDecryptedDirectMessageListener(this);
if (p2PService.isBootstrapped())
onBootstrapComplete();
else
p2PService.addP2PServiceListener(bootstrapListener);
} }
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
@ -151,6 +157,15 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
UserThread.runAfter(completeHandler::run, openOffers.size() * 100 + 200, TimeUnit.MILLISECONDS); UserThread.runAfter(completeHandler::run, openOffers.size() * 100 + 200, TimeUnit.MILLISECONDS);
} }
public void removeAllOpenOffers(@Nullable Runnable completeHandler) {
List<OpenOffer> 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 // DecryptedDirectMessageListener implementation
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -172,7 +187,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void onBootstrapComplete() { public void onBootstrapComplete() {
p2PService.removeP2PServiceListener(bootstrapListener); if (bootstrapListener != null)
p2PService.removeP2PServiceListener(bootstrapListener);
stopped = false; stopped = false;

View file

@ -409,13 +409,10 @@ public class MainViewModel implements ViewModel {
} }
private void onAllServicesInitialized() { 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 // 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. // 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() && if (walletService.getWallet().isEncrypted()) {
(openOfferManager.getOpenOffers().size() > 0
|| tradeManager.getTrades().size() > 0
|| disputeManager.getDisputesAsObservableList().size() > 0)) {
walletPasswordWindow walletPasswordWindow
.onAesKey(aesKey -> { .onAesKey(aesKey -> {
tradeWalletService.setAesKey(aesKey); tradeWalletService.setAesKey(aesKey);

View file

@ -145,9 +145,7 @@ public class PasswordView extends ActivatableView<GridPane, Void> {
addMultilineLabel(root, gridRow, addMultilineLabel(root, gridRow,
"With password protection you need to enter your password when" + "With password protection you need to enter your password when" +
" withdrawing bitcoin out of your wallet or " + " withdrawing bitcoin out of your wallet or " +
"if you want to view or restore a wallet from seed words.\n" + "if you want to view or restore a wallet from seed words as well as at application startup.",
"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.",
Layout.FIRST_ROW_AND_GROUP_DISTANCE); Layout.FIRST_ROW_AND_GROUP_DISTANCE);
} }

View file

@ -37,7 +37,6 @@ import io.bitsquare.gui.main.overlays.windows.DisputeSummaryWindow;
import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow; import io.bitsquare.gui.main.overlays.windows.TradeDetailsWindow;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.gui.util.GUIUtil; import io.bitsquare.gui.util.GUIUtil;
import io.bitsquare.p2p.BootstrapListener;
import io.bitsquare.p2p.P2PService; import io.bitsquare.p2p.P2PService;
import io.bitsquare.p2p.network.Connection; import io.bitsquare.p2p.network.Connection;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
@ -110,7 +109,6 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
private TableGroupHeadline tableGroupHeadline; private TableGroupHeadline tableGroupHeadline;
private ObservableList<DisputeCommunicationMessage> disputeCommunicationMessages; private ObservableList<DisputeCommunicationMessage> disputeCommunicationMessages;
private Button sendButton; private Button sendButton;
private boolean isBootstrapped;
private Subscription inputTextAreaTextSubscription; private Subscription inputTextAreaTextSubscription;
@ -175,17 +173,6 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
}; };
disputeDirectMessageListListener = c -> scrollToBottom(); disputeDirectMessageListListener = c -> scrollToBottom();
if (!p2PService.isBootstrapped()) {
p2PService.addP2PServiceListener(new BootstrapListener() {
@Override
public void onBootstrapComplete() {
isBootstrapped = true;
}
});
} else {
isBootstrapped = true;
}
} }
@Override @Override
@ -425,7 +412,7 @@ public class TraderDisputeView extends ActivatableView<VBox, Void> {
sendButton = new Button("Send"); sendButton = new Button("Send");
sendButton.setDefaultButton(true); sendButton.setDefaultButton(true);
sendButton.setOnAction(e -> { sendButton.setOnAction(e -> {
if (isBootstrapped) { if (p2PService.isBootstrapped()) {
String text = inputTextArea.getText(); String text = inputTextArea.getText();
if (!text.isEmpty()) if (!text.isEmpty())
onSendMessage(text, selectedDispute); onSendMessage(text, selectedDispute);

View file

@ -25,6 +25,7 @@ import io.bitsquare.btc.AddressEntryException;
import io.bitsquare.btc.Restrictions; import io.bitsquare.btc.Restrictions;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.listeners.BalanceListener; import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Utilities; import io.bitsquare.common.util.Utilities;
import io.bitsquare.gui.common.view.ActivatableView; import io.bitsquare.gui.common.view.ActivatableView;
import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.common.view.FxmlView;
@ -58,6 +59,7 @@ import org.spongycastle.crypto.params.KeyParameter;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@FxmlView @FxmlView
@ -281,7 +283,9 @@ public class WithdrawalView extends ActivatableView<VBox, Void> {
private void doWithdraw(Coin amount, FutureCallback<Transaction> callback) { private void doWithdraw(Coin amount, FutureCallback<Transaction> callback) {
if (walletService.getWallet().isEncrypted()) { 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 { } else {
sendFunds(amount, null, callback); sendFunds(amount, null, callback);
} }

View file

@ -30,7 +30,6 @@ import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.gui.Navigation; import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.ActivatableDataModel; import io.bitsquare.gui.common.model.ActivatableDataModel;
import io.bitsquare.gui.main.overlays.notifications.Notification; 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.gui.util.BSFormatter;
import io.bitsquare.locale.TradeCurrency; import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.p2p.P2PService; import io.bitsquare.p2p.P2PService;
@ -63,14 +62,13 @@ import static com.google.common.base.Preconditions.checkNotNull;
class CreateOfferDataModel extends ActivatableDataModel { class CreateOfferDataModel extends ActivatableDataModel {
private final OpenOfferManager openOfferManager; private final OpenOfferManager openOfferManager;
final WalletService walletService; final WalletService walletService;
private final TradeWalletService tradeWalletService; final TradeWalletService tradeWalletService;
private final Preferences preferences; private final Preferences preferences;
private final User user; private final User user;
private final KeyRing keyRing; private final KeyRing keyRing;
private final P2PService p2PService; private final P2PService p2PService;
private final PriceFeed priceFeed; private final PriceFeed priceFeed;
private Navigation navigation; private Navigation navigation;
private final WalletPasswordWindow walletPasswordWindow;
private final BlockchainService blockchainService; private final BlockchainService blockchainService;
private final BSFormatter formatter; private final BSFormatter formatter;
private final String offerId; private final String offerId;
@ -117,8 +115,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
@Inject @Inject
CreateOfferDataModel(OpenOfferManager openOfferManager, WalletService walletService, TradeWalletService tradeWalletService, CreateOfferDataModel(OpenOfferManager openOfferManager, WalletService walletService, TradeWalletService tradeWalletService,
Preferences preferences, User user, KeyRing keyRing, P2PService p2PService, PriceFeed priceFeed, Preferences preferences, User user, KeyRing keyRing, P2PService p2PService, PriceFeed priceFeed,
Navigation navigation, Navigation navigation, BlockchainService blockchainService, BSFormatter formatter) {
WalletPasswordWindow walletPasswordWindow, BlockchainService blockchainService, BSFormatter formatter) {
this.openOfferManager = openOfferManager; this.openOfferManager = openOfferManager;
this.walletService = walletService; this.walletService = walletService;
this.tradeWalletService = tradeWalletService; this.tradeWalletService = tradeWalletService;
@ -128,7 +125,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
this.p2PService = p2PService; this.p2PService = p2PService;
this.priceFeed = priceFeed; this.priceFeed = priceFeed;
this.navigation = navigation; this.navigation = navigation;
this.walletPasswordWindow = walletPasswordWindow;
this.blockchainService = blockchainService; this.blockchainService = blockchainService;
this.formatter = formatter; this.formatter = formatter;
@ -286,17 +282,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
} }
void onPlaceOffer(Offer offer, TransactionResultHandler resultHandler) { 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); openOfferManager.placeOffer(offer, totalToPayAsCoin.get().subtract(offerFeeAsCoin), useSavingsWallet, resultHandler);
} }

View file

@ -29,7 +29,6 @@ import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.pricefeed.PriceFeed; import io.bitsquare.btc.pricefeed.PriceFeed;
import io.bitsquare.gui.common.model.ActivatableDataModel; import io.bitsquare.gui.common.model.ActivatableDataModel;
import io.bitsquare.gui.main.overlays.notifications.Notification; 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.gui.util.BSFormatter;
import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.locale.TradeCurrency; import io.bitsquare.locale.TradeCurrency;
@ -61,10 +60,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/ */
class TakeOfferDataModel extends ActivatableDataModel { class TakeOfferDataModel extends ActivatableDataModel {
private final TradeManager tradeManager; private final TradeManager tradeManager;
private final TradeWalletService tradeWalletService; final TradeWalletService tradeWalletService;
private final WalletService walletService; final WalletService walletService;
private final User user; private final User user;
private final WalletPasswordWindow walletPasswordWindow;
private final Preferences preferences; private final Preferences preferences;
private final PriceFeed priceFeed; private final PriceFeed priceFeed;
private final BlockchainService blockchainService; private final BlockchainService blockchainService;
@ -103,14 +101,13 @@ class TakeOfferDataModel extends ActivatableDataModel {
@Inject @Inject
TakeOfferDataModel(TradeManager tradeManager, TradeWalletService tradeWalletService, TakeOfferDataModel(TradeManager tradeManager, TradeWalletService tradeWalletService,
WalletService walletService, User user, WalletPasswordWindow walletPasswordWindow, WalletService walletService, User user,
Preferences preferences, PriceFeed priceFeed, BlockchainService blockchainService, Preferences preferences, PriceFeed priceFeed, BlockchainService blockchainService,
BSFormatter formatter) { BSFormatter formatter) {
this.tradeManager = tradeManager; this.tradeManager = tradeManager;
this.tradeWalletService = tradeWalletService; this.tradeWalletService = tradeWalletService;
this.walletService = walletService; this.walletService = walletService;
this.user = user; this.user = user;
this.walletPasswordWindow = walletPasswordWindow;
this.preferences = preferences; this.preferences = preferences;
this.priceFeed = priceFeed; this.priceFeed = priceFeed;
this.blockchainService = blockchainService; 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 // 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. // have it persisted as well.
void onTakeOffer(TradeResultHandler tradeResultHandler) { 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(), tradeManager.onTakeOffer(amountAsCoin.get(),
totalToPayAsCoin.get().subtract(takerFeeAsCoin), totalToPayAsCoin.get().subtract(takerFeeAsCoin),
offer, offer,

View file

@ -62,7 +62,8 @@ public class EmptyWalletWindow extends Overlay<EmptyWalletWindow> {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @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.walletService = walletService;
this.walletPasswordWindow = walletPasswordWindow; this.walletPasswordWindow = walletPasswordWindow;
this.openOfferManager = openOfferManager; this.openOfferManager = openOfferManager;
@ -140,8 +141,23 @@ public class EmptyWalletWindow extends Overlay<EmptyWalletWindow> {
} }
private void doEmptyWallet(KeyParameter aesKey) { 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); emptyWalletButton.setDisable(true);
openOfferManager.closeAllOpenOffers(() -> { openOfferManager.removeAllOpenOffers(() -> {
try { try {
walletService.emptyWallet(addressInputTextField.getText(), walletService.emptyWallet(addressInputTextField.getText(),
aesKey, aesKey,

View file

@ -23,6 +23,7 @@ import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.AddressEntryException; import io.bitsquare.btc.AddressEntryException;
import io.bitsquare.btc.Restrictions; import io.bitsquare.btc.Restrictions;
import io.bitsquare.btc.WalletService; import io.bitsquare.btc.WalletService;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.FaultHandler; import io.bitsquare.common.handlers.FaultHandler;
import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.common.util.Tuple2; import io.bitsquare.common.util.Tuple2;
@ -47,6 +48,8 @@ import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.spongycastle.crypto.params.KeyParameter; import org.spongycastle.crypto.params.KeyParameter;
import java.util.concurrent.TimeUnit;
import static io.bitsquare.gui.util.FormBuilder.*; import static io.bitsquare.gui.util.FormBuilder.*;
public class BuyerStep5View extends TradeStepView { public class BuyerStep5View extends TradeStepView {
@ -223,8 +226,6 @@ public class BuyerStep5View extends TradeStepView {
} }
private void doWithdrawal(Coin receiverAmount) { private void doWithdrawal(Coin receiverAmount) {
useSavingsWalletButton.setDisable(true);
withdrawToExternalWalletButton.setDisable(true);
String toAddress = withdrawAddressTextField.getText(); String toAddress = withdrawAddressTextField.getText();
ResultHandler resultHandler = this::handleTradeCompleted; ResultHandler resultHandler = this::handleTradeCompleted;
FaultHandler faultHandler = (errorMessage, throwable) -> { FaultHandler faultHandler = (errorMessage, throwable) -> {
@ -236,17 +237,16 @@ public class BuyerStep5View extends TradeStepView {
new Popup().error(errorMessage).show(); new Popup().error(errorMessage).show();
}; };
if (model.dataModel.walletService.getWallet().isEncrypted()) { if (model.dataModel.walletService.getWallet().isEncrypted()) {
model.dataModel.walletPasswordWindow.onAesKey(aesKey -> doWithdrawRequest(toAddress, receiverAmount, aesKey, resultHandler, faultHandler)) UserThread.runAfter(() -> model.dataModel.walletPasswordWindow.onAesKey(aesKey ->
.onClose(() -> { doWithdrawRequest(toAddress, receiverAmount, aesKey, resultHandler, faultHandler))
useSavingsWalletButton.setDisable(false); .show(), 300, TimeUnit.MILLISECONDS);
withdrawToExternalWalletButton.setDisable(false);
})
.show();
} else } else
doWithdrawRequest(toAddress, receiverAmount, null, resultHandler, faultHandler); doWithdrawRequest(toAddress, receiverAmount, null, resultHandler, faultHandler);
} }
private void doWithdrawRequest(String toAddress, Coin receiverAmount, KeyParameter aesKey, ResultHandler resultHandler, FaultHandler faultHandler) { private void doWithdrawRequest(String toAddress, Coin receiverAmount, KeyParameter aesKey, ResultHandler resultHandler, FaultHandler faultHandler) {
useSavingsWalletButton.setDisable(true);
withdrawToExternalWalletButton.setDisable(true);
model.dataModel.onWithdrawRequest(toAddress, model.dataModel.onWithdrawRequest(toAddress,
receiverAmount, receiverAmount,
aesKey, aesKey,