From 9dd9decb96fb801062052b69d75a2a2a6ffc23eb Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Sat, 30 Jan 2016 23:43:58 +0100 Subject: [PATCH] Bugfixes, refactorings,... --- .../java/io/bitsquare/btc/AddressEntry.java | 2 +- .../io/bitsquare/btc/TradeWalletService.java | 2 +- .../BlockChainAccountContractData.java | 1 + .../java/io/bitsquare/trade/offer/Offer.java | 4 +- .../offerer/ProcessPayDepositRequest.java | 2 +- .../taker/ProcessPublishDepositTxRequest.java | 2 +- .../gui/components/TextFieldWithCopyIcon.java | 26 +++++--- .../java/io/bitsquare/gui/main/MainView.java | 18 ++--- .../disputes/trader/TraderDisputeView.java | 5 +- .../pendingtrades/steps/StartPaymentView.java | 6 +- .../bitsquare/gui/popups/ContractPopup.java | 3 +- .../java/io/bitsquare/gui/popups/Popup.java | 2 +- .../java/io/bitsquare/p2p/NodeAddress.java | 2 +- .../java/io/bitsquare/p2p/P2PService.java | 22 ++++++- .../bitsquare/p2p/network/IllegalRequest.java | 3 +- .../io/bitsquare/p2p/network/NetworkNode.java | 1 - .../io/bitsquare/p2p/peers/Broadcaster.java | 17 ++++- .../p2p/peers/PeerExchangeManager.java | 1 + .../io/bitsquare/p2p/peers/PeerManager.java | 65 +++++++++---------- .../io/bitsquare/p2p/peers/ReportedPeer.java | 13 ++-- .../p2p/peers/RequestDataManager.java | 3 +- .../bitsquare/p2p/storage/P2PDataStorage.java | 6 +- 22 files changed, 124 insertions(+), 82 deletions(-) diff --git a/core/src/main/java/io/bitsquare/btc/AddressEntry.java b/core/src/main/java/io/bitsquare/btc/AddressEntry.java index fa90137416..846b015e9c 100644 --- a/core/src/main/java/io/bitsquare/btc/AddressEntry.java +++ b/core/src/main/java/io/bitsquare/btc/AddressEntry.java @@ -121,7 +121,7 @@ public class AddressEntry implements Serializable { // For display we usually only display the first 8 characters. @Nullable public String getShortOfferId() { - return offerId != null ? offerId.substring(0, 8) : null; + return offerId != null ? offerId.substring(0, Math.min(8, offerId.length())) : null; } public Context getContext() { diff --git a/core/src/main/java/io/bitsquare/btc/TradeWalletService.java b/core/src/main/java/io/bitsquare/btc/TradeWalletService.java index d0b2a978a9..bdc8d12dfe 100644 --- a/core/src/main/java/io/bitsquare/btc/TradeWalletService.java +++ b/core/src/main/java/io/bitsquare/btc/TradeWalletService.java @@ -968,7 +968,7 @@ public class TradeWalletService { checkNotNull(input.getConnectedOutput(), "input.getConnectedOutput() must not be null"); Script scriptPubKey = input.getConnectedOutput().getScriptPubKey(); ECKey sigKey = input.getOutpoint().getConnectedKey(wallet); - checkNotNull(sigKey, "sigKey must not be null"); + checkNotNull(sigKey, "signInput: sigKey must not be null. input.getOutpoint()=" + input.getOutpoint().toString()); Sha256Hash hash = transaction.hashForSignature(inputIndex, scriptPubKey, Transaction.SigHash.ALL, false); ECKey.ECDSASignature signature = sigKey.sign(hash, aesKey); TransactionSignature txSig = new TransactionSignature(signature, Transaction.SigHash.ALL, false); diff --git a/core/src/main/java/io/bitsquare/payment/BlockChainAccountContractData.java b/core/src/main/java/io/bitsquare/payment/BlockChainAccountContractData.java index 37435e162b..ccdce971d6 100644 --- a/core/src/main/java/io/bitsquare/payment/BlockChainAccountContractData.java +++ b/core/src/main/java/io/bitsquare/payment/BlockChainAccountContractData.java @@ -26,6 +26,7 @@ public class BlockChainAccountContractData extends PaymentAccountContractData im private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; private String address; + // used in crypto note coins. not supported now but hopefully in future, so leave it for now. private String paymentId; public BlockChainAccountContractData(String paymentMethod, String id, int maxTradePeriod) { diff --git a/core/src/main/java/io/bitsquare/trade/offer/Offer.java b/core/src/main/java/io/bitsquare/trade/offer/Offer.java index 7bfc80ab8b..61950ac916 100644 --- a/core/src/main/java/io/bitsquare/trade/offer/Offer.java +++ b/core/src/main/java/io/bitsquare/trade/offer/Offer.java @@ -198,7 +198,7 @@ public final class Offer implements PubKeyProtectedExpirablePayload { } public String getReferenceText() { - return id.substring(0, 8); + return id.substring(0, Math.min(8, id.length())); } @@ -263,7 +263,7 @@ public final class Offer implements PubKeyProtectedExpirablePayload { } public String getShortId() { - return id.substring(0, 8); + return id.substring(0, Math.min(8, id.length())); } public NodeAddress getOffererNodeAddress() { diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/ProcessPayDepositRequest.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/ProcessPayDepositRequest.java index 1f8fcfcd77..2d76fe5e00 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/ProcessPayDepositRequest.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/ProcessPayDepositRequest.java @@ -66,7 +66,7 @@ public class ProcessPayDepositRequest extends TradeTask { // We apply the payment ID in case its a cryptoNote coin. It is created form the hash of the trade ID if (paymentAccountContractData instanceof BlockChainAccountContractData && CurrencyUtil.isCryptoNoteCoin(processModel.getOffer().getCurrencyCode())) { - String paymentId = Hash.getHashAsHex(trade.getId()).substring(0, 32); + String paymentId = Hash.getHashAsHex(trade.getId()).substring(0, Math.min(32, trade.getId().length())); ((BlockChainAccountContractData) paymentAccountContractData).setPaymentId(paymentId); } diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/ProcessPublishDepositTxRequest.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/ProcessPublishDepositTxRequest.java index db67ca0943..2628b7c010 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/ProcessPublishDepositTxRequest.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/ProcessPublishDepositTxRequest.java @@ -54,7 +54,7 @@ public class ProcessPublishDepositTxRequest extends TradeTask { // We apply the payment ID in case its a cryptoNote coin. It is created form the hash of the trade ID if (paymentAccountContractData instanceof BlockChainAccountContractData && CurrencyUtil.isCryptoNoteCoin(processModel.getOffer().getCurrencyCode())) { - String paymentId = Hash.getHashAsHex(trade.getId()).substring(0, 32); + String paymentId = Hash.getHashAsHex(trade.getId()).substring(0, Math.min(32, trade.getId().length())); ((BlockChainAccountContractData) paymentAccountContractData).setPaymentId(paymentId); } diff --git a/gui/src/main/java/io/bitsquare/gui/components/TextFieldWithCopyIcon.java b/gui/src/main/java/io/bitsquare/gui/components/TextFieldWithCopyIcon.java index 1a3c485965..746b1339e8 100644 --- a/gui/src/main/java/io/bitsquare/gui/components/TextFieldWithCopyIcon.java +++ b/gui/src/main/java/io/bitsquare/gui/components/TextFieldWithCopyIcon.java @@ -27,13 +27,11 @@ import javafx.scene.control.TextField; import javafx.scene.control.Tooltip; import javafx.scene.layout.AnchorPane; -import java.util.function.Consumer; - public class TextFieldWithCopyIcon extends AnchorPane { private final StringProperty text = new SimpleStringProperty(); private final TextField textField; - private Consumer handler; + private boolean copyWithoutCurrencyPostFix; /////////////////////////////////////////////////////////////////////////////////////////// @@ -48,10 +46,19 @@ public class TextFieldWithCopyIcon extends AnchorPane { AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY); AnchorPane.setRightAnchor(copyIcon, 0.0); copyIcon.setOnMouseClicked(e -> { - if (getText() != null && getText().length() > 0) { - Utilities.copyToClipboard(getText()); - if (handler != null) - handler.accept(getText()); + String text = getText(); + if (text != null && text.length() > 0) { + String copyText; + if (copyWithoutCurrencyPostFix) { + String[] strings = text.split(" "); + if (strings.length > 1) + copyText = strings[0]; // exclude the BTC postfix + else + copyText = text; + } else { + copyText = text; + } + Utilities.copyToClipboard(copyText); } }); textField = new TextField(); @@ -85,7 +92,8 @@ public class TextFieldWithCopyIcon extends AnchorPane { this.text.set(text); } - public void setHandler(Consumer handler) { - this.handler = handler; + public void setCopyWithoutCurrencyPostFix(boolean copyWithoutCurrencyPostFix) { + this.copyWithoutCurrencyPostFix = copyWithoutCurrencyPostFix; } + } diff --git a/gui/src/main/java/io/bitsquare/gui/main/MainView.java b/gui/src/main/java/io/bitsquare/gui/main/MainView.java index e20443832c..75384cb28c 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/MainView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/MainView.java @@ -54,20 +54,20 @@ public class MainView extends InitializableView { public static final String TITLE_KEY = "view.title"; - public static BorderPane getBaseApplicationContainer() { - return baseApplicationContainer; + public static StackPane getRootContainer() { + return MainView.rootContainer; } public static void blur() { - transitions.blur(MainView.base); + transitions.blur(MainView.rootContainer); } public static void blurLight() { - transitions.blur(MainView.base, Transitions.DEFAULT_DURATION, true, false, 5); + transitions.blur(MainView.rootContainer, Transitions.DEFAULT_DURATION, true, false, 5); } public static void removeBlur() { - transitions.removeBlur(baseApplicationContainer); + transitions.removeBlur(MainView.rootContainer); } private final ToggleGroup navButtons = new ToggleGroup(); @@ -86,9 +86,9 @@ public class MainView extends InitializableView { private ProgressBar btcSyncIndicator; private Label btcSplashInfo; private List persistedFilesCorrupted; - private static BorderPane baseApplicationContainer; - private static StackPane base; + private BorderPane baseApplicationContainer; private Popup p2PNetworkWarnMsgPopup, btcNetworkWarnMsgPopup; + private static StackPane rootContainer; @Inject public MainView(MainViewModel model, CachingViewLoader viewLoader, Navigation navigation, Transitions transitions, @@ -102,8 +102,8 @@ public class MainView extends InitializableView { @Override protected void initialize() { - MainView.base = this.root; - + MainView.rootContainer = this.root; + ToggleButton marketButton = new NavButton(MarketView.class, "Market"); ToggleButton buyButton = new NavButton(BuyOfferView.class, "Buy BTC"); ToggleButton sellButton = new NavButton(SellOfferView.class, "Sell BTC"); 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 f61fff8f10..8a0d69eaeb 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 @@ -225,7 +225,8 @@ public class TraderDisputeView extends ActivatableView { private void onRequestUpload() { if (tempAttachments.size() < 3) { FileChooser fileChooser = new FileChooser(); - fileChooser.setTitle("Open file to attach"); + int maxSizeInKB = Connection.getMaxMsgSize() / 1024; + fileChooser.setTitle("Open file to attach (max. file size: " + maxSizeInKB + " kb)"); /* if (Utilities.isUnix()) fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));*/ File result = fileChooser.showOpenDialog(stage); @@ -238,7 +239,7 @@ public class TraderDisputeView extends ActivatableView { tempAttachments.add(new DisputeDirectMessage.Attachment(result.getName(), filesAsBytes)); inputTextArea.setText(inputTextArea.getText() + "\n[Attachment " + result.getName() + "]"); } else { - new Popup().error("The max. allowed file size is 100 kB.").show(); + new Popup().error("The max. allowed file size is " + maxSizeInKB + " kB.").show(); } } catch (java.io.IOException e) { e.printStackTrace(); diff --git a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/StartPaymentView.java b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/StartPaymentView.java index 19d19cc3b1..3924132d8b 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/StartPaymentView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/portfolio/pendingtrades/steps/StartPaymentView.java @@ -19,6 +19,7 @@ package io.bitsquare.gui.main.portfolio.pendingtrades.steps; import io.bitsquare.app.BitsquareApp; import io.bitsquare.common.util.Tuple3; +import io.bitsquare.gui.components.TextFieldWithCopyIcon; import io.bitsquare.gui.components.TitledGroupBg; import io.bitsquare.gui.components.TxIdTextField; import io.bitsquare.gui.components.paymentmethods.*; @@ -208,8 +209,9 @@ public class StartPaymentView extends TradeStepDetailsView { txIdTextField = addLabelTxIdTextField(gridPane, gridRow, "Deposit transaction ID:", Layout.FIRST_ROW_DISTANCE).second; TitledGroupBg accountTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, "Payments details", Layout.GROUP_DISTANCE); - addLabelTextFieldWithCopyIcon(gridPane, gridRow, "Amount to transfer:", model.getFiatAmount(), - Layout.FIRST_ROW_AND_GROUP_DISTANCE); + TextFieldWithCopyIcon field = addLabelTextFieldWithCopyIcon(gridPane, gridRow, "Amount to transfer:", model.getFiatAmount(), + Layout.FIRST_ROW_AND_GROUP_DISTANCE).second; + field.setCopyWithoutCurrencyPostFix(true); PaymentAccountContractData paymentAccountContractData = model.dataModel.getSellersPaymentAccountContractData(); String paymentMethodName = paymentAccountContractData.getPaymentMethodName(); diff --git a/gui/src/main/java/io/bitsquare/gui/popups/ContractPopup.java b/gui/src/main/java/io/bitsquare/gui/popups/ContractPopup.java index 4664511c2c..41e625289c 100644 --- a/gui/src/main/java/io/bitsquare/gui/popups/ContractPopup.java +++ b/gui/src/main/java/io/bitsquare/gui/popups/ContractPopup.java @@ -103,6 +103,7 @@ public class ContractPopup extends Popup { if (sellerPaymentAccountContractData instanceof BlockChainAccountContractData && ((BlockChainAccountContractData) sellerPaymentAccountContractData).getPaymentId() != null) { rows++; + isPaymentIdAvailable = true; } addTitledGroupBg(gridPane, ++rowIndex, rows, "Contract"); addLabelTextFieldWithCopyIcon(gridPane, rowIndex, "Offer ID:", offer.getId(), @@ -123,7 +124,7 @@ public class ContractPopup extends Popup { addLabelTextField(gridPane, ++rowIndex, "Selected arbitrator:", contract.arbitratorNodeAddress.getFullAddress()); addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "Buyer payment details:", BSResources.get(contract.getBuyerPaymentAccountContractData().getPaymentDetails())).second.setMouseTransparent(false); - addLabelTextField(gridPane, ++rowIndex, "Seller payment details:", + addLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, "Seller payment details:", BSResources.get(sellerPaymentAccountContractData.getPaymentDetails())).second.setMouseTransparent(false); if (isPaymentIdAvailable) addLabelTextField(gridPane, ++rowIndex, "Seller payment ID:", diff --git a/gui/src/main/java/io/bitsquare/gui/popups/Popup.java b/gui/src/main/java/io/bitsquare/gui/popups/Popup.java index 753f7bd7bd..2083ed5981 100644 --- a/gui/src/main/java/io/bitsquare/gui/popups/Popup.java +++ b/gui/src/main/java/io/bitsquare/gui/popups/Popup.java @@ -208,7 +208,7 @@ public class Popup { protected void createPopup() { if (owner == null) - owner = MainView.getBaseApplicationContainer(); + owner = MainView.getRootContainer(); stage = new Stage(); Scene scene = new Scene(gridPane); diff --git a/network/src/main/java/io/bitsquare/p2p/NodeAddress.java b/network/src/main/java/io/bitsquare/p2p/NodeAddress.java index 40b2857e97..c008d3d9aa 100644 --- a/network/src/main/java/io/bitsquare/p2p/NodeAddress.java +++ b/network/src/main/java/io/bitsquare/p2p/NodeAddress.java @@ -28,7 +28,7 @@ public class NodeAddress implements Serializable { // We use just a few chars form or address to blur the potential receiver for sent messages public byte[] getAddressPrefixHash() { if (addressPrefixHash == null) - addressPrefixHash = Hash.getHash(getFullAddress().substring(0, 2)); + addressPrefixHash = Hash.getHash(getFullAddress().substring(0, Math.min(2, getFullAddress().length()))); return addressPrefixHash; } diff --git a/network/src/main/java/io/bitsquare/p2p/P2PService.java b/network/src/main/java/io/bitsquare/p2p/P2PService.java index cfa9853e2e..6ce7c98eaf 100644 --- a/network/src/main/java/io/bitsquare/p2p/P2PService.java +++ b/network/src/main/java/io/bitsquare/p2p/P2PService.java @@ -80,6 +80,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis private ChangeListener connectionNodeAddressListener; private Subscription networkReadySubscription; private boolean isBootstrapped; + private ChangeListener numOfBroadcastsChangeListener; /////////////////////////////////////////////////////////////////////////////////////////// @@ -537,18 +538,35 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis log.debug("remove result=" + result); sendMailboxMessageListener.onFault("A timeout occurred when trying to broadcast mailbox data."); }, 30); - broadcaster.addOneTimeListener(message -> { + Broadcaster.Listener listener = message -> { if (message instanceof AddDataMessage && ((AddDataMessage) message).data.equals(protectedMailboxData)) { sendMailboxMessageListener.onStoredInMailbox(); sendMailboxMessageTimeoutTimer.cancel(); } - }); + }; + broadcaster.addListener(listener); + if (numOfBroadcastsChangeListener != null) { + log.warn("numOfBroadcastsChangeListener should be null"); + broadcaster.getNumOfBroadcastsProperty().removeListener(numOfBroadcastsChangeListener); + } + numOfBroadcastsChangeListener = (observable, oldValue, newValue) -> { + // We want to get at least 1 successful broadcast + if ((int) newValue > 0) + broadcaster.removeListener(listener); + UserThread.execute(() -> { + broadcaster.getNumOfBroadcastsProperty().removeListener(numOfBroadcastsChangeListener); + numOfBroadcastsChangeListener = null; + }); + }; + broadcaster.getNumOfBroadcastsProperty().addListener(numOfBroadcastsChangeListener); boolean result = p2PDataStorage.add(protectedMailboxData, networkNode.getNodeAddress()); if (!result) { sendMailboxMessageTimeoutTimer.cancel(); + broadcaster.removeListener(listener); + broadcaster.getNumOfBroadcastsProperty().removeListener(numOfBroadcastsChangeListener); sendMailboxMessageListener.onFault("Data already exists in our local database"); boolean result2 = p2PDataStorage.remove(protectedMailboxData, networkNode.getNodeAddress()); log.debug("remove result=" + result2); diff --git a/network/src/main/java/io/bitsquare/p2p/network/IllegalRequest.java b/network/src/main/java/io/bitsquare/p2p/network/IllegalRequest.java index 2f5acade23..cf98878d8e 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/IllegalRequest.java +++ b/network/src/main/java/io/bitsquare/p2p/network/IllegalRequest.java @@ -3,7 +3,8 @@ package io.bitsquare.p2p.network; public enum IllegalRequest { MaxSizeExceeded(1), InvalidDataType(0), - WrongNetworkId(0); + WrongNetworkId(0), + TooManyMessages(1); public final int maxTolerance; diff --git a/network/src/main/java/io/bitsquare/p2p/network/NetworkNode.java b/network/src/main/java/io/bitsquare/p2p/network/NetworkNode.java index 250e39292a..93bf1cf09e 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/NetworkNode.java +++ b/network/src/main/java/io/bitsquare/p2p/network/NetworkNode.java @@ -107,7 +107,6 @@ public abstract class NetworkNode implements MessageListener, ConnectionListener return outboundConnection; } catch (Throwable throwable) { if (!(throwable instanceof ConnectException || throwable instanceof IOException)) { - throwable.printStackTrace(); log.error("Executing task failed. " + throwable.getMessage()); } throw throwable; diff --git a/network/src/main/java/io/bitsquare/p2p/peers/Broadcaster.java b/network/src/main/java/io/bitsquare/p2p/peers/Broadcaster.java index 013c2ec40f..346e5f56c7 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/Broadcaster.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/Broadcaster.java @@ -8,6 +8,8 @@ import io.bitsquare.p2p.NodeAddress; import io.bitsquare.p2p.network.Connection; import io.bitsquare.p2p.network.NetworkNode; import io.bitsquare.p2p.storage.messages.DataBroadcastMessage; +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleIntegerProperty; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -27,12 +29,16 @@ public class Broadcaster { private final NetworkNode networkNode; private final Set listeners = new CopyOnWriteArraySet<>(); + + private IntegerProperty numOfBroadcasts = new SimpleIntegerProperty(0); + public Broadcaster(NetworkNode networkNode) { this.networkNode = networkNode; } public void broadcast(DataBroadcastMessage message, @Nullable NodeAddress sender) { Log.traceCall("Sender " + sender + ". Message " + message.toString()); + numOfBroadcasts.set(0); Set receivers = networkNode.getConfirmedConnections(); if (!receivers.isEmpty()) { log.info("Broadcast message to {} peers. Message: {}", receivers.size(), message); @@ -46,9 +52,9 @@ public class Broadcaster { @Override public void onSuccess(Connection connection) { log.trace("Broadcast to " + connection + " succeeded."); + numOfBroadcasts.set(numOfBroadcasts.get() + 1); listeners.stream().forEach(listener -> { listener.onBroadcasted(message); - listeners.remove(listener); }); } @@ -64,9 +70,16 @@ public class Broadcaster { } } + public IntegerProperty getNumOfBroadcastsProperty() { + return numOfBroadcasts; + } + // That listener gets immediately removed after the handler is called - public void addOneTimeListener(Listener listener) { + public void addListener(Listener listener) { listeners.add(listener); } + public void removeListener(Listener listener) { + listeners.remove(listener); + } } diff --git a/network/src/main/java/io/bitsquare/p2p/peers/PeerExchangeManager.java b/network/src/main/java/io/bitsquare/p2p/peers/PeerExchangeManager.java index 718bd0eba6..018802fa53 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/PeerExchangeManager.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/PeerExchangeManager.java @@ -253,6 +253,7 @@ public class PeerExchangeManager implements MessageListener, ConnectionListener !peerManager.isConfirmed(e)) .collect(Collectors.toList()) .stream() + .filter(e -> e.lastActivityDate != null) .sorted((o1, o2) -> o2.lastActivityDate.compareTo(o1.lastActivityDate)) .map(e -> e.nodeAddress) .collect(Collectors.toList()); diff --git a/network/src/main/java/io/bitsquare/p2p/peers/PeerManager.java b/network/src/main/java/io/bitsquare/p2p/peers/PeerManager.java index cee4ec14dd..aec1a374ba 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/PeerManager.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/PeerManager.java @@ -8,7 +8,6 @@ import io.bitsquare.p2p.network.*; import io.bitsquare.p2p.peers.messages.data.UpdateDataRequest; import io.bitsquare.storage.Storage; import javafx.beans.value.ChangeListener; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,13 +43,13 @@ public class PeerManager implements ConnectionListener, MessageListener { private static final int MAX_REPORTED_PEERS = 1000; private static final int MAX_PERSISTED_PEERS = 500; - private static final long MAX_AGE = 14 * 24 * 60 * 60 * 1000; // max age for reported peers is 14 days + private static final long DAY = 24 * 60 * 60 * 1000; // max age for reported peers is 14 days + private static final long MAX_AGE = 14 * DAY; // max age for reported peers is 14 days private final NetworkNode networkNode; private final Set seedNodeAddresses; - @Nullable - private Storage> dbStorage; + private final Storage> dbStorage; private final HashSet persistedPeers = new HashSet<>(); private final Set reportedPeers = new HashSet<>(); @@ -66,7 +65,12 @@ public class PeerManager implements ConnectionListener, MessageListener { this.networkNode = networkNode; this.seedNodeAddresses = new HashSet<>(seedNodeAddresses); networkNode.addConnectionListener(this); - createDbStorage(storageDir); + dbStorage = new Storage<>(storageDir); + HashSet persistedPeers = dbStorage.initAndGetPersisted("persistedPeers"); + if (persistedPeers != null) { + log.info("We have persisted reported peers. persistedPeers.size()=" + persistedPeers.size()); + this.persistedPeers.addAll(persistedPeers); + } connectionNodeAddressListener = (observable, oldValue, newValue) -> { // Every time we get a new peer connected with a known address we check if we need to remove peers @@ -79,21 +83,6 @@ public class PeerManager implements ConnectionListener, MessageListener { }; } - private void createDbStorage(File storageDir) { - dbStorage = new Storage<>(storageDir); - initPersistedPeers(); - } - - private void initPersistedPeers() { - if (dbStorage != null) { - HashSet persistedPeers = dbStorage.initAndGetPersisted("persistedPeers"); - if (persistedPeers != null) { - log.info("We have persisted reported peers. persistedPeers.size()=" + persistedPeers.size()); - this.persistedPeers.addAll(persistedPeers); - } - } - } - public void shutDown() { Log.traceCall(); @@ -124,10 +113,15 @@ public class PeerManager implements ConnectionListener, MessageListener { public void onDisconnect(Reason reason, Connection connection) { connection.getNodeAddressProperty().removeListener(connectionNodeAddressListener); connection.getPeersNodeAddressOptional().ifPresent(nodeAddress -> { - ReportedPeer reportedPeer = new ReportedPeer(nodeAddress); - reportedPeers.remove(reportedPeer); - persistedPeers.add(reportedPeer); - dbStorage.queueUpForSave(persistedPeers, 5000); + penalizeUnreachablePeer(nodeAddress); + Optional reportedPeerOptional = reportedPeers.stream() + .filter(e -> e.nodeAddress.equals(nodeAddress)).findAny(); + if (reportedPeerOptional.isPresent()) { + ReportedPeer reportedPeer = reportedPeerOptional.get(); + reportedPeers.remove(reportedPeer); + persistedPeers.add(reportedPeer); + dbStorage.queueUpForSave(persistedPeers, 5000); + } }); } @@ -215,12 +209,14 @@ public class PeerManager implements ConnectionListener, MessageListener { private void removeTooOldReportedPeers() { Set reportedPeersToRemove = reportedPeers.stream() - .filter(reportedPeer -> new Date().getTime() - reportedPeer.lastActivityDate.getTime() > MAX_AGE) + .filter(reportedPeer -> reportedPeer.lastActivityDate != null && + new Date().getTime() - reportedPeer.lastActivityDate.getTime() > MAX_AGE) .collect(Collectors.toSet()); reportedPeersToRemove.forEach(this::removeReportedPeer); Set persistedPeersToRemove = persistedPeers.stream() - .filter(reportedPeer -> new Date().getTime() - reportedPeer.lastActivityDate.getTime() > MAX_AGE) + .filter(reportedPeer -> reportedPeer.lastActivityDate != null && + new Date().getTime() - reportedPeer.lastActivityDate.getTime() > MAX_AGE) .collect(Collectors.toSet()); persistedPeersToRemove.forEach(this::removeFromPersistedPeers); } @@ -312,6 +308,7 @@ public class PeerManager implements ConnectionListener, MessageListener { if (toRemove2 > 0) { // now we remove second half with a list sorted by oldest lastActivityDate list = new ArrayList<>(persistedPeers); + list = list.stream().filter(e -> e.lastActivityDate != null).collect(Collectors.toList()); list.sort((o1, o2) -> o1.lastActivityDate.compareTo(o2.lastActivityDate)); for (int i = 0; i < toRemove2; i++) { persistedPeers.remove(list.get(i)); @@ -330,10 +327,11 @@ public class PeerManager implements ConnectionListener, MessageListener { private void printReportedPeers() { if (!reportedPeers.isEmpty()) { StringBuilder result = new StringBuilder("\n\n------------------------------------------------------------\n" + - "Reported peers for node " + networkNode.getNodeAddress() + ":"); + "Reported peers:"); reportedPeers.stream().forEach(e -> result.append("\n").append(e)); result.append("\n------------------------------------------------------------\n"); - log.info(result.toString()); + log.debug(result.toString()); + log.info("Number of reported peers: {}", reportedPeers.size()); } } @@ -372,21 +370,16 @@ public class PeerManager implements ConnectionListener, MessageListener { reportedPeers.stream() .filter(reportedPeer -> reportedPeer.nodeAddress.equals(nodeAddress)) .findAny() - .ifPresent(this::adjustLastActivityDate); + .ifPresent(ReportedPeer::penalizeLastActivityDate); persistedPeers.stream() .filter(reportedPeer -> reportedPeer.nodeAddress.equals(nodeAddress)) .findAny() .ifPresent(reportedPeer -> { - adjustLastActivityDate(reportedPeer); + reportedPeer.penalizeLastActivityDate(); dbStorage.queueUpForSave(persistedPeers, 5000); }); - } - private void adjustLastActivityDate(ReportedPeer reportedPeer) { - long now = new Date().getTime(); - long diff = now - reportedPeer.lastActivityDate.getTime(); - long reduced = now - diff * 2; - reportedPeer.setLastActivityDate(new Date(reduced)); + removeTooOldReportedPeers(); } public Set getConnectedAndReportedPeers() { diff --git a/network/src/main/java/io/bitsquare/p2p/peers/ReportedPeer.java b/network/src/main/java/io/bitsquare/p2p/peers/ReportedPeer.java index b5af6c9b4d..a81478da41 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/ReportedPeer.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/ReportedPeer.java @@ -18,12 +18,13 @@ public class ReportedPeer implements Serializable { this.lastActivityDate = lastActivityDate; } - public ReportedPeer(NodeAddress nodeAddress) { - this(nodeAddress, null); - } - - public void setLastActivityDate(Date lastActivityDate) { - this.lastActivityDate = lastActivityDate; + public void penalizeLastActivityDate() { + if (lastActivityDate != null) { + long now = new Date().getTime(); + long diff = Math.max(24 * 60 * 60 * 1000, now - lastActivityDate.getTime()); + long reduced = now - diff * 2; + lastActivityDate = new Date(reduced); + } } // We don't use the lastActivityDate for identity diff --git a/network/src/main/java/io/bitsquare/p2p/peers/RequestDataManager.java b/network/src/main/java/io/bitsquare/p2p/peers/RequestDataManager.java index 54c6177ee7..eceacf5402 100644 --- a/network/src/main/java/io/bitsquare/p2p/peers/RequestDataManager.java +++ b/network/src/main/java/io/bitsquare/p2p/peers/RequestDataManager.java @@ -173,7 +173,7 @@ public class RequestDataManager implements MessageListener { errorMessage, nodeAddress); peerManager.penalizeUnreachablePeer(nodeAddress); - + if (!remainingNodeAddresses.isEmpty()) { log.info("There are remaining nodes available for requesting data. " + "We will try requestDataFromPeers again."); @@ -233,6 +233,7 @@ public class RequestDataManager implements MessageListener { !peerManager.isSelf(e)) .collect(Collectors.toList()) .stream() + .filter(e -> e.lastActivityDate != null) .sorted((o1, o2) -> o2.lastActivityDate.compareTo(o1.lastActivityDate)) .map(e -> e.nodeAddress) .collect(Collectors.toList()); diff --git a/network/src/main/java/io/bitsquare/p2p/storage/P2PDataStorage.java b/network/src/main/java/io/bitsquare/p2p/storage/P2PDataStorage.java index 0bacc97c07..b0a5238a68 100644 --- a/network/src/main/java/io/bitsquare/p2p/storage/P2PDataStorage.java +++ b/network/src/main/java/io/bitsquare/p2p/storage/P2PDataStorage.java @@ -161,7 +161,8 @@ public class P2PDataStorage implements MessageListener { StringBuilder sb = new StringBuilder("\n\n------------------------------------------------------------\n"); sb.append("Data set after addProtectedExpirableData (truncated)"); - map.values().stream().forEach(e -> sb.append("\n").append(e.toString().substring(0, 40)).append("...\n")); + map.values().stream().forEach(e -> sb.append("\n").append(e.toString() + .substring(0, Math.min(50, e.toString().length()))).append("...\n")); sb.append("\n------------------------------------------------------------\n"); log.trace(sb.toString()); log.info("Data set after addProtectedExpirableData: size=" + map.values().size()); @@ -280,7 +281,8 @@ public class P2PDataStorage implements MessageListener { StringBuilder sb = new StringBuilder("\n\n------------------------------------------------------------\n" + "Data set after removeProtectedExpirableData: (truncated)"); - map.values().stream().forEach(e -> sb.append("\n").append(e.toString().substring(0, 40)).append("...\n")); + map.values().stream().forEach(e -> sb.append("\n").append(e.toString() + .substring(0, Math.min(50, e.toString().length()))).append("...\n")); sb.append("\n------------------------------------------------------------\n"); log.trace(sb.toString()); log.info("Data set after addProtectedExpirableData: size=" + map.values().size());