From 232c5b46ff9e081938bb99639c06a4b2e057c115 Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Fri, 30 Oct 2015 00:42:20 +0100 Subject: [PATCH] add ui checks for un-authenticated node, fix broadcast issue --- .../java/io/bitsquare/alert/AlertManager.java | 4 +- .../java/io/bitsquare/alert/AlertService.java | 6 +- .../arbitration/ArbitratorManager.java | 4 +- .../arbitration/ArbitratorService.java | 6 +- .../trade/offer/OfferBookService.java | 6 +- .../java/io/bitsquare/app/BitsquareApp.java | 7 +- .../ArbitratorRegistrationView.java | 22 ++- .../ArbitratorRegistrationViewModel.java | 4 + .../createoffer/CreateOfferDataModel.java | 10 +- .../offer/createoffer/CreateOfferView.java | 21 +- .../createoffer/CreateOfferViewModel.java | 21 +- .../gui/main/offer/offerbook/OfferBook.java | 4 +- .../offer/offerbook/OfferBookListItem.java | 15 ++ .../main/offer/offerbook/OfferBookView.java | 40 ++-- .../offer/offerbook/OfferBookViewModel.java | 9 +- .../openoffer/OpenOffersDataModel.java | 2 + .../portfolio/openoffer/OpenOffersView.java | 40 ++-- .../openoffer/OpenOffersViewModel.java | 8 +- .../pendingtrades/PendingTradesViewModel.java | 10 +- .../steps/ConfirmPaymentReceivedView.java | 16 +- .../pendingtrades/steps/StartPaymentView.java | 16 +- .../java/io/bitsquare/p2p/P2PService.java | 180 ++++++++++-------- ...tener.java => HashMapChangedListener.java} | 2 +- .../ProtectedExpirableDataStorage.java | 84 ++++---- .../p2p/storage/data/ProtectedData.java | 11 +- 25 files changed, 329 insertions(+), 219 deletions(-) rename network/src/main/java/io/bitsquare/p2p/storage/{HashSetChangedListener.java => HashMapChangedListener.java} (80%) diff --git a/core/src/main/java/io/bitsquare/alert/AlertManager.java b/core/src/main/java/io/bitsquare/alert/AlertManager.java index fec210fd0c..222702836b 100644 --- a/core/src/main/java/io/bitsquare/alert/AlertManager.java +++ b/core/src/main/java/io/bitsquare/alert/AlertManager.java @@ -19,7 +19,7 @@ package io.bitsquare.alert; import com.google.inject.Inject; import io.bitsquare.common.crypto.KeyRing; -import io.bitsquare.p2p.storage.HashSetChangedListener; +import io.bitsquare.p2p.storage.HashMapChangedListener; import io.bitsquare.p2p.storage.data.ProtectedData; import io.bitsquare.user.User; import javafx.beans.property.ObjectProperty; @@ -59,7 +59,7 @@ public class AlertManager { this.keyRing = keyRing; this.user = user; - alertService.addHashSetChangedListener(new HashSetChangedListener() { + alertService.addHashSetChangedListener(new HashMapChangedListener() { @Override public void onAdded(ProtectedData entry) { Serializable data = entry.expirablePayload; diff --git a/core/src/main/java/io/bitsquare/alert/AlertService.java b/core/src/main/java/io/bitsquare/alert/AlertService.java index da1f8b43c2..9ef4158975 100644 --- a/core/src/main/java/io/bitsquare/alert/AlertService.java +++ b/core/src/main/java/io/bitsquare/alert/AlertService.java @@ -20,7 +20,7 @@ package io.bitsquare.alert; import io.bitsquare.common.handlers.ErrorMessageHandler; import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.p2p.P2PService; -import io.bitsquare.p2p.storage.HashSetChangedListener; +import io.bitsquare.p2p.storage.HashMapChangedListener; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,8 +45,8 @@ public class AlertService { this.p2PService = p2PService; } - public void addHashSetChangedListener(HashSetChangedListener hashSetChangedListener) { - p2PService.addHashSetChangedListener(hashSetChangedListener); + public void addHashSetChangedListener(HashMapChangedListener hashMapChangedListener) { + p2PService.addHashSetChangedListener(hashMapChangedListener); } public void addAlertMessage(Alert alert, @Nullable ResultHandler resultHandler, @Nullable ErrorMessageHandler errorMessageHandler) { diff --git a/core/src/main/java/io/bitsquare/arbitration/ArbitratorManager.java b/core/src/main/java/io/bitsquare/arbitration/ArbitratorManager.java index bf9a76204b..fab4719c4d 100644 --- a/core/src/main/java/io/bitsquare/arbitration/ArbitratorManager.java +++ b/core/src/main/java/io/bitsquare/arbitration/ArbitratorManager.java @@ -26,7 +26,7 @@ import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.p2p.Address; import io.bitsquare.p2p.P2PService; import io.bitsquare.p2p.P2PServiceListener; -import io.bitsquare.p2p.storage.HashSetChangedListener; +import io.bitsquare.p2p.storage.HashMapChangedListener; import io.bitsquare.p2p.storage.data.ProtectedData; import io.bitsquare.user.User; import javafx.collections.FXCollections; @@ -95,7 +95,7 @@ public class ArbitratorManager { this.arbitratorService = arbitratorService; this.user = user; - arbitratorService.addHashSetChangedListener(new HashSetChangedListener() { + arbitratorService.addHashSetChangedListener(new HashMapChangedListener() { @Override public void onAdded(ProtectedData entry) { applyArbitrators(); diff --git a/core/src/main/java/io/bitsquare/arbitration/ArbitratorService.java b/core/src/main/java/io/bitsquare/arbitration/ArbitratorService.java index 2cf612904b..2cb85d6ea6 100644 --- a/core/src/main/java/io/bitsquare/arbitration/ArbitratorService.java +++ b/core/src/main/java/io/bitsquare/arbitration/ArbitratorService.java @@ -21,7 +21,7 @@ import io.bitsquare.common.handlers.ErrorMessageHandler; import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.p2p.Address; import io.bitsquare.p2p.P2PService; -import io.bitsquare.p2p.storage.HashSetChangedListener; +import io.bitsquare.p2p.storage.HashMapChangedListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,8 +51,8 @@ public class ArbitratorService { this.p2PService = p2PService; } - public void addHashSetChangedListener(HashSetChangedListener hashSetChangedListener) { - p2PService.addHashSetChangedListener(hashSetChangedListener); + public void addHashSetChangedListener(HashMapChangedListener hashMapChangedListener) { + p2PService.addHashSetChangedListener(hashMapChangedListener); } public void addArbitrator(Arbitrator arbitrator, final ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { diff --git a/core/src/main/java/io/bitsquare/trade/offer/OfferBookService.java b/core/src/main/java/io/bitsquare/trade/offer/OfferBookService.java index 1f1eaca69a..d4d6211c76 100644 --- a/core/src/main/java/io/bitsquare/trade/offer/OfferBookService.java +++ b/core/src/main/java/io/bitsquare/trade/offer/OfferBookService.java @@ -20,7 +20,7 @@ package io.bitsquare.trade.offer; import io.bitsquare.common.handlers.ErrorMessageHandler; import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.p2p.P2PService; -import io.bitsquare.p2p.storage.HashSetChangedListener; +import io.bitsquare.p2p.storage.HashMapChangedListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,8 +47,8 @@ public class OfferBookService { this.p2PService = p2PService; } - public void addHashSetChangedListener(HashSetChangedListener hashSetChangedListener) { - p2PService.addHashSetChangedListener(hashSetChangedListener); + public void addHashSetChangedListener(HashMapChangedListener hashMapChangedListener) { + p2PService.addHashSetChangedListener(hashMapChangedListener); } public void addOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { diff --git a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java index 301126b569..96cfcff31b 100644 --- a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java +++ b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java @@ -34,6 +34,7 @@ import io.bitsquare.gui.common.view.guice.InjectorViewFactory; import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.debug.DebugView; import io.bitsquare.gui.popups.EmptyWalletPopup; +import io.bitsquare.gui.popups.Popup; import io.bitsquare.gui.popups.SendAlertMessagePopup; import io.bitsquare.gui.util.ImageUtil; import io.bitsquare.p2p.P2PService; @@ -213,11 +214,7 @@ public class BitsquareApp extends Application { try { throwable.printStackTrace(); try { - Dialogs.create() - .owner(primaryStage) - .title("Error") - .message("A fatal exception occurred at startup.") - .showException(throwable); + new Popup().error(throwable.getMessage()).show(); } catch (Throwable throwable3) { log.error("Error at displaying Throwable."); throwable3.printStackTrace(); diff --git a/gui/src/main/java/io/bitsquare/gui/main/account/arbitratorregistration/ArbitratorRegistrationView.java b/gui/src/main/java/io/bitsquare/gui/main/account/arbitratorregistration/ArbitratorRegistrationView.java index c94df4349e..4cbf14f7d5 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/account/arbitratorregistration/ArbitratorRegistrationView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/account/arbitratorregistration/ArbitratorRegistrationView.java @@ -219,14 +219,24 @@ public class ArbitratorRegistrationView extends ActivatableViewAndModel new Popup().information("You have successfully removed your arbitrator from the P2P network.").show(), - (errorMessage) -> new Popup().error("Could not remove arbitrator.\nError message: " + errorMessage).show()); + if (model.isAuthenticated()) { + model.onRevoke( + () -> new Popup().information("You have successfully removed your arbitrator from the P2P network.").show(), + (errorMessage) -> new Popup().error("Could not remove arbitrator.\nError message: " + errorMessage).show()); + } else { + new Popup().warning("You need to wait until your client is authenticated in the network.\n" + + "That might take up to about 2 minutes at startup.").show(); + } } private void onRegister() { - model.onRegister( - () -> new Popup().information("You have successfully registered your arbitrator to the P2P network.").show(), - (errorMessage) -> new Popup().error("Could not register arbitrator.\nError message: " + errorMessage).show()); + if (model.isAuthenticated()) { + model.onRegister( + () -> new Popup().information("You have successfully registered your arbitrator to the P2P network.").show(), + (errorMessage) -> new Popup().error("Could not register arbitrator.\nError message: " + errorMessage).show()); + } else { + new Popup().warning("You need to wait until your client is authenticated in the network.\n" + + "That might take up to about 2 minutes at startup.").show(); + } } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/account/arbitratorregistration/ArbitratorRegistrationViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/account/arbitratorregistration/ArbitratorRegistrationViewModel.java index 8fd16d07b9..4890571811 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/account/arbitratorregistration/ArbitratorRegistrationViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/account/arbitratorregistration/ArbitratorRegistrationViewModel.java @@ -183,4 +183,8 @@ class ArbitratorRegistrationViewModel extends ActivatableViewModel { registrationEditDisabled.set(!allDataValid || myArbitratorProperty.get() != null); revokeButtonDisabled.set(!allDataValid || myArbitratorProperty.get() == null); } + + boolean isAuthenticated() { + return p2PService.isAuthenticated(); + } } 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 7ff5591ae5..c7e8f92ac8 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.gui.popups.WalletPasswordPopup; import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.locale.Country; import io.bitsquare.locale.TradeCurrency; -import io.bitsquare.p2p.Address; import io.bitsquare.p2p.P2PService; import io.bitsquare.payment.PaymentAccount; import io.bitsquare.payment.SepaAccount; @@ -51,6 +50,8 @@ import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.UUID; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Domain for that UI element. * Note that the create offer domain has a deeper scope in the application domain (TradeManager). @@ -62,8 +63,8 @@ class CreateOfferDataModel extends ActivatableDataModel { private final TradeWalletService tradeWalletService; private final Preferences preferences; private final User user; - private final Address address; private final KeyRing keyRing; + private P2PService p2PService; private final WalletPasswordPopup walletPasswordPopup; private final BSFormatter formatter; private final String offerId; @@ -110,10 +111,10 @@ class CreateOfferDataModel extends ActivatableDataModel { this.preferences = preferences; this.user = user; this.keyRing = keyRing; + this.p2PService = p2PService; this.walletPasswordPopup = walletPasswordPopup; this.formatter = formatter; - address = p2PService.getAddress(); offerId = UUID.randomUUID().toString(); addressEntry = walletService.getAddressEntryByOfferId(offerId); offerFeeAsCoin = FeePolicy.CREATE_OFFER_FEE; @@ -199,8 +200,9 @@ class CreateOfferDataModel extends ActivatableDataModel { // That is optional and set to null if not supported (AltCoins, OKPay,...) Country country = paymentAccount.getCountry(); + checkNotNull(p2PService.getAddress(), "Address must not be null"); return new Offer(offerId, - address, + p2PService.getAddress(), keyRing.getPubKeyRing(), direction, fiatPrice, diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java index fbf3327785..22eeec0781 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferView.java @@ -201,17 +201,22 @@ public class CreateOfferView extends ActivatableViewAndModel model.onPlaceOffer(o)).show(offer); - } else { - if (model.hasAcceptedArbitrators()) { - model.onPlaceOffer(offer); + if (model.isAuthenticated()) { + if (model.getShowPlaceOfferConfirmation()) { + offerDetailsPopup.onPlaceOffer(o -> model.onPlaceOffer(o)).show(offer); } else { - new Popup().warning("You have no arbitrator selected.\n" + - "Please select at least one arbitrator.").show(); + if (model.hasAcceptedArbitrators()) { + model.onPlaceOffer(offer); + } else { + new Popup().warning("You have no arbitrator selected.\n" + + "Please select at least one arbitrator.").show(); - navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class, ArbitratorSelectionView.class); + navigation.navigateTo(MainView.class, AccountView.class, AccountSettingsView.class, ArbitratorSelectionView.class); + } } + } else { + new Popup().warning("You need to wait until your client is authenticated in the network.\n" + + "That might take up to about 2 minutes at startup.").show(); } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferViewModel.java index eeec6024b0..8ad8e8f1c8 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/offer/createoffer/CreateOfferViewModel.java @@ -26,6 +26,7 @@ import io.bitsquare.gui.util.validation.FiatValidator; import io.bitsquare.gui.util.validation.InputValidator; import io.bitsquare.locale.BSResources; import io.bitsquare.locale.TradeCurrency; +import io.bitsquare.p2p.P2PService; import io.bitsquare.payment.PaymentAccount; import io.bitsquare.trade.offer.Offer; import javafx.beans.property.*; @@ -42,6 +43,7 @@ import static javafx.beans.binding.Bindings.createStringBinding; class CreateOfferViewModel extends ActivatableWithDataModel implements ViewModel { private final BtcValidator btcValidator; + private P2PService p2PService; private final BSFormatter formatter; private final FiatValidator fiatValidator; @@ -100,11 +102,13 @@ class CreateOfferViewModel extends ActivatableWithDataModel { - log.debug("Remove offer was successful"); - new Popup().information("You can withdraw the funds you paid in from the funds screens.").show(); - navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class); - }, - (message) -> { - log.error(message); - new Popup().warning("Remove offer failed:\n" + message).show(); - }); + if (model.isAuthenticated()) { + model.onRemoveOpenOffer(offer, + () -> { + log.debug("Remove offer was successful"); + new Popup().information("You can withdraw the funds you paid in from the funds screens.").show(); + navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class); + }, + (message) -> { + log.error(message); + new Popup().warning("Remove offer failed:\n" + message).show(); + }); + } else { + new Popup().warning("You need to wait until your client is authenticated in the network.\n" + + "That might take up to about 2 minutes at startup.").show(); + } } private void showWarning(String masthead, String message, Class target) { @@ -446,8 +454,7 @@ public class OfferBookView extends ActivatableViewAndModel onTakeOffer(offer)); } - } - else { + } else { title = "Not matching"; iconView.setId(null); button.setOnAction(e -> onShowInfo(isPaymentAccountValidForOffer, hasMatchingArbitrator)); @@ -455,8 +462,7 @@ public class OfferBookView extends ActivatableViewAndModel filteredItems; @@ -69,7 +71,7 @@ class OfferBookViewModel extends ActivatableViewModel { @Inject public OfferBookViewModel(User user, OpenOfferManager openOfferManager, OfferBook offerBook, - Preferences preferences, + Preferences preferences, P2PService p2PService, BSFormatter formatter) { super(); @@ -77,6 +79,7 @@ class OfferBookViewModel extends ActivatableViewModel { this.user = user; this.offerBook = offerBook; this.preferences = preferences; + this.p2PService = p2PService; this.formatter = formatter; offerBookListItems = offerBook.getOfferBookListItems(); @@ -155,6 +158,10 @@ class OfferBookViewModel extends ActivatableViewModel { return list; } + boolean isAuthenticated() { + return p2PService.isAuthenticated(); + } + public TradeCurrency getTradeCurrency() { return tradeCurrency; } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/openoffer/OpenOffersDataModel.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/openoffer/OpenOffersDataModel.java index f04d9139bb..7edeeee33c 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/openoffer/OpenOffersDataModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/openoffer/OpenOffersDataModel.java @@ -75,4 +75,6 @@ class OpenOffersDataModel extends ActivatableDataModel { // we sort by date, earliest first list.sort((o1, o2) -> o2.getOffer().getDate().compareTo(o1.getOffer().getDate())); } + + } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/openoffer/OpenOffersView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/openoffer/OpenOffersView.java index 92d0d051fb..50ca36f1a9 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/openoffer/OpenOffersView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/openoffer/OpenOffersView.java @@ -38,8 +38,10 @@ import javax.inject.Inject; @FxmlView public class OpenOffersView extends ActivatableViewAndModel { - @FXML TableView table; - @FXML TableColumn priceColumn, amountColumn, volumeColumn, + @FXML + TableView table; + @FXML + TableColumn priceColumn, amountColumn, volumeColumn, directionColumn, dateColumn, offerIdColumn, removeItemColumn; private final Navigation navigation; private final OfferDetailsPopup offerDetailsPopup; @@ -71,18 +73,22 @@ public class OpenOffersView extends ActivatableViewAndModel { - log.debug("Remove offer was successful"); - new Popup().information("You can withdraw the funds you paid in from the funds screens.") - .onClose(() -> navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class)) - .show(); - }, - (message) -> { - log.error(message); - new Popup().warning("Remove offer failed:\n" + message).show(); - }); - + if (model.isAuthenticated()) { + model.onCancelOpenOffer(openOffer, + () -> { + log.debug("Remove offer was successful"); + new Popup().information("You can withdraw the funds you paid in from the funds screens.") + .onClose(() -> navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class)) + .show(); + }, + (message) -> { + log.error(message); + new Popup().warning("Remove offer failed:\n" + message).show(); + }); + } else { + new Popup().warning("You need to wait until your client is authenticated in the network.\n" + + "That might take up to about 2 minutes at startup.").show(); + } } /* private void openOfferDetails(OpenOfferListItem item) { @@ -144,8 +150,7 @@ public class OpenOffersView extends ActivatableViewAndModel offerDetailsPopup.show(item.getOffer())); setGraphic(hyperlink); - } - else { + } else { setGraphic(null); setId(null); } @@ -281,8 +286,7 @@ public class OpenOffersView extends ActivatableViewAndModel onCancelOpenOffer(item.getOpenOffer())); setGraphic(button); - } - else { + } else { setGraphic(null); } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/openoffer/OpenOffersViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/openoffer/OpenOffersViewModel.java index 568386e4d1..b2749f9019 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/openoffer/OpenOffersViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/openoffer/OpenOffersViewModel.java @@ -23,16 +23,19 @@ import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.gui.common.model.ActivatableWithDataModel; import io.bitsquare.gui.common.model.ViewModel; import io.bitsquare.gui.util.BSFormatter; +import io.bitsquare.p2p.P2PService; import io.bitsquare.trade.offer.OpenOffer; import javafx.collections.ObservableList; class OpenOffersViewModel extends ActivatableWithDataModel implements ViewModel { + private P2PService p2PService; private final BSFormatter formatter; @Inject - public OpenOffersViewModel(OpenOffersDataModel dataModel, BSFormatter formatter) { + public OpenOffersViewModel(OpenOffersDataModel dataModel, P2PService p2PService, BSFormatter formatter) { super(dataModel); + this.p2PService = p2PService; this.formatter = formatter; } @@ -70,4 +73,7 @@ class OpenOffersViewModel extends ActivatableWithDataModel return formatter.formatDateTime(item.getOffer().getDate()); } + boolean isAuthenticated() { + return p2PService.isAuthenticated(); + } } diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesViewModel.java index fab95c2942..f655eb829d 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/PendingTradesViewModel.java @@ -24,6 +24,7 @@ import io.bitsquare.gui.common.model.ViewModel; import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.validation.*; import io.bitsquare.locale.BSResources; +import io.bitsquare.p2p.P2PService; import io.bitsquare.payment.PaymentMethod; import io.bitsquare.trade.Trade; import javafx.beans.property.*; @@ -72,6 +73,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel buyerState = new SimpleObjectProperty<>(PendingTradesViewModel.BuyerState.UNDEFINED); private final ObjectProperty sellerState = new SimpleObjectProperty<>(UNDEFINED); @@ -92,7 +94,8 @@ public class PendingTradesViewModel extends ActivatableWithDataModel future = sendMessage(address, + new GetDataSetMessage(addToListAndGetNonce())); + Futures.addCallback(future, new FutureCallback() { + @Override + public void onSuccess(@Nullable Connection connection) { + log.info("onPeerAddressAuthenticated Send GetAllDataMessage to " + address + " succeeded."); + connectedSeedNodes.add(address); + } + + @Override + public void onFailure(Throwable throwable) { + log.warn("onPeerAddressAuthenticated Send GetAllDataMessage to " + address + " failed. " + + "Exception:" + throwable.getMessage()); + } + }); + } P2PService.this.authenticated = true; dataStorage.setAuthenticated(true); @@ -182,15 +203,18 @@ public class P2PService { HashSet set = ((DataSetMessage) message).set; set.stream().forEach(e -> dataStorage.add(e, connection.getPeerAddress())); - set.stream().filter(e -> e instanceof ProtectedMailboxData).forEach(e -> tryDecryptMailboxData((ProtectedMailboxData) e)); + // TODO done in addHashSetChangedListener + // set.stream().filter(e -> e instanceof ProtectedMailboxData).forEach(e -> tryDecryptMailboxData((ProtectedMailboxData) e)); dataReceived(); } else if (message instanceof SealedAndSignedMessage) { - try { - DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerifyMessage((SealedAndSignedMessage) message); - UserThread.execute(() -> decryptedMailListeners.stream().forEach(e -> e.onMailMessage(decryptedMessageWithPubKey, connection.getPeerAddress()))); - } catch (CryptoException e) { - log.info("Decryption of SealedAndSignedMessage failed. That is expected if the message is not intended for us."); + if (encryptionService != null) { + try { + DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerifyMessage((SealedAndSignedMessage) message); + UserThread.execute(() -> decryptedMailListeners.stream().forEach(e -> e.onMailMessage(decryptedMessageWithPubKey, connection.getPeerAddress()))); + } catch (CryptoException e) { + log.info("Decryption of SealedAndSignedMessage failed. That is expected if the message is not intended for us."); + } } } }); @@ -217,7 +241,7 @@ public class P2PService { } }); - dataStorage.addHashSetChangedListener(new HashSetChangedListener() { + dataStorage.addHashMapChangedListener(new HashMapChangedListener() { @Override public void onAdded(ProtectedData entry) { if (entry instanceof ProtectedMailboxData) @@ -317,24 +341,26 @@ public class P2PService { } private void doSendEncryptedMailMessage(Address peerAddress, PubKeyRing pubKeyRing, MailMessage message, SendMailMessageListener sendMailMessageListener) { - try { - SealedAndSignedMessage sealedAndSignedMessage = encryptionService.encryptAndSignMessage(pubKeyRing, message); - SettableFuture future = sendMessage(peerAddress, sealedAndSignedMessage); - Futures.addCallback(future, new FutureCallback() { - @Override - public void onSuccess(@Nullable Connection connection) { - UserThread.execute(() -> sendMailMessageListener.onArrived()); - } + if (encryptionService != null) { + try { + SealedAndSignedMessage sealedAndSignedMessage = encryptionService.encryptAndSignMessage(pubKeyRing, message); + SettableFuture future = sendMessage(peerAddress, sealedAndSignedMessage); + Futures.addCallback(future, new FutureCallback() { + @Override + public void onSuccess(@Nullable Connection connection) { + UserThread.execute(() -> sendMailMessageListener.onArrived()); + } - @Override - public void onFailure(Throwable throwable) { - throwable.printStackTrace(); - UserThread.execute(() -> sendMailMessageListener.onFault()); - } - }); - } catch (CryptoException e) { - e.printStackTrace(); - UserThread.execute(() -> sendMailMessageListener.onFault()); + @Override + public void onFailure(Throwable throwable) { + throwable.printStackTrace(); + UserThread.execute(() -> sendMailMessageListener.onFault()); + } + }); + } catch (CryptoException e) { + e.printStackTrace(); + UserThread.execute(() -> sendMailMessageListener.onFault()); + } } } @@ -358,34 +384,36 @@ public class P2PService { } private void trySendEncryptedMailboxMessage(Address peerAddress, PubKeyRing peersPubKeyRing, MailboxMessage message, SendMailboxMessageListener sendMailboxMessageListener) { - try { - SealedAndSignedMessage sealedAndSignedMessage = encryptionService.encryptAndSignMessage(peersPubKeyRing, message); - SettableFuture future = sendMessage(peerAddress, sealedAndSignedMessage); - Futures.addCallback(future, new FutureCallback() { - @Override - public void onSuccess(@Nullable Connection connection) { - log.trace("SendEncryptedMailboxMessage onSuccess"); - UserThread.execute(() -> sendMailboxMessageListener.onArrived()); - } + if (encryptionService != null) { + try { + SealedAndSignedMessage sealedAndSignedMessage = encryptionService.encryptAndSignMessage(peersPubKeyRing, message); + SettableFuture future = sendMessage(peerAddress, sealedAndSignedMessage); + Futures.addCallback(future, new FutureCallback() { + @Override + public void onSuccess(@Nullable Connection connection) { + log.trace("SendEncryptedMailboxMessage onSuccess"); + UserThread.execute(() -> sendMailboxMessageListener.onArrived()); + } - @Override - public void onFailure(Throwable throwable) { - log.trace("SendEncryptedMailboxMessage onFailure"); - log.debug(throwable.toString()); - log.info("We cannot send message to peer. Peer might be offline. We will store message in mailbox."); - log.trace("create MailboxEntry with peerAddress " + peerAddress); - PublicKey receiverStoragePublicKey = peersPubKeyRing.getStorageSignaturePubKey(); - addMailboxData(new ExpirableMailboxPayload(sealedAndSignedMessage, - keyRing.getStorageSignatureKeyPair().getPublic(), - receiverStoragePublicKey), - receiverStoragePublicKey); - UserThread.execute(() -> sendMailboxMessageListener.onStoredInMailbox()); - } - }); - } catch (CryptoException e) { - e.printStackTrace(); - log.error("sendEncryptedMessage failed"); - UserThread.execute(() -> sendMailboxMessageListener.onFault()); + @Override + public void onFailure(Throwable throwable) { + log.trace("SendEncryptedMailboxMessage onFailure"); + log.debug(throwable.toString()); + log.info("We cannot send message to peer. Peer might be offline. We will store message in mailbox."); + log.trace("create MailboxEntry with peerAddress " + peerAddress); + PublicKey receiverStoragePublicKey = peersPubKeyRing.getStorageSignaturePubKey(); + addMailboxData(new ExpirableMailboxPayload(sealedAndSignedMessage, + keyRing.getStorageSignatureKeyPair().getPublic(), + receiverStoragePublicKey), + receiverStoragePublicKey); + UserThread.execute(() -> sendMailboxMessageListener.onStoredInMailbox()); + } + }); + } catch (CryptoException e) { + e.printStackTrace(); + log.error("sendEncryptedMessage failed"); + UserThread.execute(() -> sendMailboxMessageListener.onFault()); + } } } @@ -481,8 +509,8 @@ public class P2PService { p2pServiceListeners.remove(listener); } - public void addHashSetChangedListener(HashSetChangedListener hashSetChangedListener) { - dataStorage.addHashSetChangedListener(hashSetChangedListener); + public void addHashSetChangedListener(HashMapChangedListener hashMapChangedListener) { + dataStorage.addHashMapChangedListener(hashMapChangedListener); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -598,29 +626,31 @@ public class P2PService { } private void tryDecryptMailboxData(ProtectedMailboxData mailboxData) { - ExpirablePayload data = mailboxData.expirablePayload; - if (data instanceof ExpirableMailboxPayload) { - ExpirableMailboxPayload mailboxEntry = (ExpirableMailboxPayload) data; - SealedAndSignedMessage sealedAndSignedMessage = mailboxEntry.sealedAndSignedMessage; - try { - DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerifyMessage(sealedAndSignedMessage); - if (decryptedMessageWithPubKey.message instanceof MailboxMessage) { - MailboxMessage mailboxMessage = (MailboxMessage) decryptedMessageWithPubKey.message; - Address senderAddress = mailboxMessage.getSenderAddress(); - checkNotNull(senderAddress, "senderAddress must not be null for mailbox messages"); + if (encryptionService != null) { + ExpirablePayload data = mailboxData.expirablePayload; + if (data instanceof ExpirableMailboxPayload) { + ExpirableMailboxPayload mailboxEntry = (ExpirableMailboxPayload) data; + SealedAndSignedMessage sealedAndSignedMessage = mailboxEntry.sealedAndSignedMessage; + try { + DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerifyMessage(sealedAndSignedMessage); + if (decryptedMessageWithPubKey.message instanceof MailboxMessage) { + MailboxMessage mailboxMessage = (MailboxMessage) decryptedMessageWithPubKey.message; + Address senderAddress = mailboxMessage.getSenderAddress(); + checkNotNull(senderAddress, "senderAddress must not be null for mailbox messages"); - log.trace("mailboxData.publicKey " + mailboxData.ownerStoragePubKey.hashCode()); - log.trace("keyRing.getStorageSignatureKeyPair().getPublic() " + keyRing.getStorageSignatureKeyPair().getPublic().hashCode()); - log.trace("keyRing.getMsgSignatureKeyPair().getPublic() " + keyRing.getMsgSignatureKeyPair().getPublic().hashCode()); - log.trace("keyRing.getMsgEncryptionKeyPair().getPublic() " + keyRing.getMsgEncryptionKeyPair().getPublic().hashCode()); + log.trace("mailboxData.publicKey " + mailboxData.ownerStoragePubKey.hashCode()); + log.trace("keyRing.getStorageSignatureKeyPair().getPublic() " + keyRing.getStorageSignatureKeyPair().getPublic().hashCode()); + log.trace("keyRing.getMsgSignatureKeyPair().getPublic() " + keyRing.getMsgSignatureKeyPair().getPublic().hashCode()); + log.trace("keyRing.getMsgEncryptionKeyPair().getPublic() " + keyRing.getMsgEncryptionKeyPair().getPublic().hashCode()); - mailboxMap.put(decryptedMessageWithPubKey, mailboxData); - log.trace("Decryption of SealedAndSignedMessage succeeded. senderAddress=" + senderAddress + " / my address=" + getAddress()); - UserThread.execute(() -> decryptedMailboxListeners.stream().forEach(e -> e.onMailboxMessageAdded(decryptedMessageWithPubKey, senderAddress))); + mailboxMap.put(decryptedMessageWithPubKey, mailboxData); + log.trace("Decryption of SealedAndSignedMessage succeeded. senderAddress=" + senderAddress + " / my address=" + getAddress()); + UserThread.execute(() -> decryptedMailboxListeners.stream().forEach(e -> e.onMailboxMessageAdded(decryptedMessageWithPubKey, senderAddress))); + } + } catch (CryptoException e) { + log.trace("Decryption of SealedAndSignedMessage failed. That is expected if the message is not intended for us."); } - } catch (CryptoException e) { - log.trace("Decryption of SealedAndSignedMessage failed. That is expected if the message is not intended for us."); } } } diff --git a/network/src/main/java/io/bitsquare/p2p/storage/HashSetChangedListener.java b/network/src/main/java/io/bitsquare/p2p/storage/HashMapChangedListener.java similarity index 80% rename from network/src/main/java/io/bitsquare/p2p/storage/HashSetChangedListener.java rename to network/src/main/java/io/bitsquare/p2p/storage/HashMapChangedListener.java index a927cba57e..4bf6f5efad 100644 --- a/network/src/main/java/io/bitsquare/p2p/storage/HashSetChangedListener.java +++ b/network/src/main/java/io/bitsquare/p2p/storage/HashMapChangedListener.java @@ -2,7 +2,7 @@ package io.bitsquare.p2p.storage; import io.bitsquare.p2p.storage.data.ProtectedData; -public interface HashSetChangedListener { +public interface HashMapChangedListener { void onAdded(ProtectedData entry); void onRemoved(ProtectedData entry); diff --git a/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java b/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java index a18e063abb..1f56c1e0fe 100644 --- a/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java +++ b/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java @@ -31,7 +31,7 @@ public class ProtectedExpirableDataStorage { private final Routing routing; private final Map map = new ConcurrentHashMap<>(); - private final List hashSetChangedListeners = new CopyOnWriteArrayList<>(); + private final List hashMapChangedListeners = new CopyOnWriteArrayList<>(); private ConcurrentHashMap sequenceNumberMap = new ConcurrentHashMap<>(); private final Storage storage; private boolean authenticated; @@ -104,12 +104,26 @@ public class ProtectedExpirableDataStorage { BigInteger hashOfPayload = getHashAsBigInteger(protectedData.expirablePayload); boolean containsKey = map.containsKey(hashOfPayload); boolean result = checkPublicKeys(protectedData, true) - && isSequenceNrValid(protectedData, hashOfPayload) - && checkSignature(protectedData) - && (!containsKey || checkIfStoredDataMatchesNewData(protectedData, hashOfPayload)) - && doAddProtectedExpirableData(protectedData, hashOfPayload, sender); + && checkSignature(protectedData); + + if (containsKey) { + result &= checkIfStoredDataMatchesNewData(protectedData, hashOfPayload) + && isSequenceNrValid(protectedData, hashOfPayload); + } if (result) { + map.put(hashOfPayload, protectedData); + log.trace("Data added to our map and it will be broadcasted to our neighbors."); + UserThread.execute(() -> hashMapChangedListeners.stream().forEach(e -> e.onAdded(protectedData))); + + StringBuilder sb = new StringBuilder("\n\nSet after addProtectedExpirableData:\n"); + map.values().stream().forEach(e -> sb.append(e.toString() + "\n\n")); + sb.append("\n\n"); + log.trace(sb.toString()); + + if (!containsKey) + broadcast(new AddDataMessage(protectedData), sender); + sequenceNumberMap.put(hashOfPayload, protectedData.sequenceNumber); storage.queueUpForSave(); } else { @@ -126,10 +140,14 @@ public class ProtectedExpirableDataStorage { && checkPublicKeys(protectedData, false) && isSequenceNrValid(protectedData, hashOfPayload) && checkSignature(protectedData) - && checkIfStoredDataMatchesNewData(protectedData, hashOfPayload) - && doRemoveProtectedExpirableData(protectedData, hashOfPayload, sender); + && checkIfStoredDataMatchesNewData(protectedData, hashOfPayload); + if (result) { + doRemoveProtectedExpirableData(protectedData, hashOfPayload); + + broadcast(new RemoveDataMessage(protectedData), sender); + sequenceNumberMap.put(hashOfPayload, protectedData.sequenceNumber); storage.queueUpForSave(); } else { @@ -147,10 +165,13 @@ public class ProtectedExpirableDataStorage { && isSequenceNrValid(protectedMailboxData, hashOfData) && protectedMailboxData.receiversPubKey.equals(protectedMailboxData.ownerStoragePubKey) // at remove both keys are the same (only receiver is able to remove data) && checkSignature(protectedMailboxData) - && checkIfStoredMailboxDataMatchesNewMailboxData(protectedMailboxData, hashOfData) - && doRemoveProtectedExpirableData(protectedMailboxData, hashOfData, sender); + && checkIfStoredMailboxDataMatchesNewMailboxData(protectedMailboxData, hashOfData); if (result) { + doRemoveProtectedExpirableData(protectedMailboxData, hashOfData); + + broadcast(new RemoveMailboxDataMessage(protectedMailboxData), sender); + sequenceNumberMap.put(hashOfData, protectedMailboxData.sequenceNumber); storage.queueUpForSave(); } else { @@ -190,8 +211,8 @@ public class ProtectedExpirableDataStorage { return new ProtectedMailboxData(expirableMailboxPayload, expirableMailboxPayload.getTTL(), storageSignaturePubKey.getPublic(), sequenceNumber, signature, receiversPublicKey); } - public void addHashSetChangedListener(HashSetChangedListener hashSetChangedListener) { - hashSetChangedListeners.add(hashSetChangedListener); + public void addHashMapChangedListener(HashMapChangedListener hashMapChangedListener) { + hashMapChangedListeners.add(hashMapChangedListener); } public void addMessageListener(MessageListener messageListener) { @@ -203,11 +224,22 @@ public class ProtectedExpirableDataStorage { // Private /////////////////////////////////////////////////////////////////////////////////////////// + private void doRemoveProtectedExpirableData(ProtectedData protectedData, BigInteger hashOfPayload) { + map.remove(hashOfPayload); + log.trace("Data removed from our map. We broadcast the message to our neighbors."); + UserThread.execute(() -> hashMapChangedListeners.stream().forEach(e -> e.onRemoved(protectedData))); + + StringBuilder sb = new StringBuilder("\n\nSet after removeProtectedExpirableData:\n"); + map.values().stream().forEach(e -> sb.append(e.toString() + "\n\n")); + sb.append("\n\n"); + log.trace(sb.toString()); + } + private boolean isSequenceNrValid(ProtectedData data, BigInteger hashOfData) { int newSequenceNumber = data.sequenceNumber; Integer storedSequenceNumber = sequenceNumberMap.get(hashOfData); if (sequenceNumberMap.containsKey(hashOfData) && newSequenceNumber <= storedSequenceNumber) { - log.warn("Sequence number is invalid. That might happen in rare cases. newSequenceNumber=" + log.warn("Sequence number is invalid. newSequenceNumber=" + newSequenceNumber + " / storedSequenceNumber=" + storedSequenceNumber); return false; } else { @@ -274,34 +306,6 @@ public class ProtectedExpirableDataStorage { } } - private boolean doAddProtectedExpirableData(ProtectedData data, BigInteger hashOfData, Address sender) { - map.put(hashOfData, data); - log.trace("Data added to our map and it will be broadcasted to our neighbors."); - UserThread.execute(() -> hashSetChangedListeners.stream().forEach(e -> e.onAdded(data))); - broadcast(new AddDataMessage(data), sender); - - StringBuilder sb = new StringBuilder("\n\nSet after addProtectedExpirableData:\n"); - map.values().stream().forEach(e -> sb.append(e.toString() + "\n\n")); - sb.append("\n\n"); - log.trace(sb.toString()); - return true; - } - - private boolean doRemoveProtectedExpirableData(ProtectedData data, BigInteger hashOfData, Address sender) { - map.remove(hashOfData); - log.trace("Data removed from our map. We broadcast the message to our neighbors."); - UserThread.execute(() -> hashSetChangedListeners.stream().forEach(e -> e.onRemoved(data))); - if (data instanceof ProtectedMailboxData) - broadcast(new RemoveMailboxDataMessage((ProtectedMailboxData) data), sender); - else - broadcast(new RemoveDataMessage(data), sender); - - StringBuilder sb = new StringBuilder("\n\nSet after removeProtectedExpirableData:\n"); - map.values().stream().forEach(e -> sb.append(e.toString() + "\n\n")); - sb.append("\n\n"); - log.trace(sb.toString()); - return true; - } private void broadcast(BroadcastMessage message, Address sender) { if (authenticated) { diff --git a/network/src/main/java/io/bitsquare/p2p/storage/data/ProtectedData.java b/network/src/main/java/io/bitsquare/p2p/storage/data/ProtectedData.java index 4edb5d7e97..fb15d79663 100644 --- a/network/src/main/java/io/bitsquare/p2p/storage/data/ProtectedData.java +++ b/network/src/main/java/io/bitsquare/p2p/storage/data/ProtectedData.java @@ -19,7 +19,7 @@ public class ProtectedData implements Serializable { public final int sequenceNumber; public final byte[] signature; @VisibleForTesting - public Date date; + transient public Date date; public ProtectedData(ExpirablePayload expirablePayload, long ttl, PublicKey ownerStoragePubKey, int sequenceNumber, byte[] signature) { this.expirablePayload = expirablePayload; @@ -34,15 +34,6 @@ public class ProtectedData implements Serializable { try { in.defaultReadObject(); ttl = expirablePayload.getTTL(); - - // in case the reported creation date is in the future - // we reset the date to the current time - if (date.getTime() > new Date().getTime()) { - log.warn("Date of object is in future. " + - "That might be ok as clocks are not synced but could be also a spam attack. " + - "date=" + date + " / now=" + new Date()); - date = new Date(); - } date = new Date(); } catch (Throwable t) {